diff options
author | Chris Xiong <chirs241097@gmail.com> | 2018-02-03 00:55:26 +0800 |
---|---|---|
committer | Chris Xiong <chirs241097@gmail.com> | 2018-02-03 00:55:26 +0800 |
commit | 1eb88d4f5d5cb05d62be1d4a0c88c7399f7c0de0 (patch) | |
tree | 4daf8fa3f4e8fff38a61b8e2da752df8b519f232 /smelt/glfw_m | |
parent | 6f955e10a71e364f527ea654156ea83785e9ada8 (diff) | |
download | SMELT-1eb88d4f5d5cb05d62be1d4a0c88c7399f7c0de0.tar.xz |
Added the GL 3.2+ port.
Fixed poor performance of the truetype renderer.
(Partially) Fixed texture locking.
Minor addition and fixes to the math library.
Diffstat (limited to 'smelt/glfw_m')
l--------- | smelt/glfw_m/CxImage | 1 | ||||
-rw-r--r-- | smelt/glfw_m/gfx_glfw.cpp | 1045 | ||||
-rw-r--r-- | smelt/glfw_m/inp_glfw.cpp | 204 | ||||
-rw-r--r-- | smelt/glfw_m/makefile | 27 | ||||
-rw-r--r-- | smelt/glfw_m/sfx_dumb.cpp | 63 | ||||
-rw-r--r-- | smelt/glfw_m/sfx_oal.cpp | 368 | ||||
-rw-r--r-- | smelt/glfw_m/smelt_config.hpp | 30 | ||||
-rw-r--r-- | smelt/glfw_m/smelt_internal.hpp | 249 | ||||
-rw-r--r-- | smelt/glfw_m/smmath_priv.hpp | 165 | ||||
-rw-r--r-- | smelt/glfw_m/sys_glfw.cpp | 334 |
10 files changed, 2486 insertions, 0 deletions
diff --git a/smelt/glfw_m/CxImage b/smelt/glfw_m/CxImage new file mode 120000 index 0000000..07300ae --- /dev/null +++ b/smelt/glfw_m/CxImage @@ -0,0 +1 @@ +../glfw/CxImage
\ No newline at end of file diff --git a/smelt/glfw_m/gfx_glfw.cpp b/smelt/glfw_m/gfx_glfw.cpp new file mode 100644 index 0000000..ebd24bf --- /dev/null +++ b/smelt/glfw_m/gfx_glfw.cpp @@ -0,0 +1,1045 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * GFX implementation based on GLFW/OpenGL 3.2+ + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * + */ +#include "smelt_internal.hpp" +#include "CxImage/ximage.h" +#include "smmath_priv.hpp" +#define dbg printf("%d: 0x%X\n",__LINE__,glGetError()) +static const char* GFX_GLFW_SRCFN="smelt/glfw_m/gfx_glfw.cpp"; +static const char* fixedfunc_pipeline_vsh= + "#version 330 core\n" + "layout (location=0) in vec3 vp;" + "layout (location=1) in vec4 vc;" + "layout (location=2) in vec2 vtc;" + "out vec4 fc;" + "out vec2 ftc;" + "uniform mat4 mmodv;" + "uniform mat4 mproj;" + "void main(){" + "gl_Position=mproj*mmodv*vec4(vp,1.0f);" + "ftc=vec2(vtc.x,1.0f-vtc.y);"//do flipping at a lower level + "fc=vc;" + "}" +; +static const char* fixedfunc_pipeline_fsh= + "#version 330 core\n" + "in vec4 fc;" + "in vec2 ftc;" + "out vec4 color;" + "uniform sampler2D tex;" + "void main(){" + "color=fc*texture(tex,ftc);" + "if(color.a<1./256.)discard;"//alpha testing + "}" +; +struct glTexture +{ + GLuint name,rw,rh,dw,dh; + const char *fn; + DWORD *px,*locpx; + bool isTarget,lost,roloc; + GLint locx,locy,locw,loch; +}; +bool SMELT_IMPL::smRenderBegin2D(bool ztest,SMTRG trg) +{ + TRenderTargetList *targ=(TRenderTargetList*)trg; + if(vertexArray) + {smLog("%s:" SLINE ": Last frame not closed.\n",GFX_GLFW_SRCFN);return false;} + glBindFramebuffer(GL_FRAMEBUFFER,(targ)?targ->frame:0); + glDepthFunc(GL_GEQUAL); + ztest?glEnable(GL_DEPTH_TEST):glDisable(GL_DEPTH_TEST); + zbufenabled=ztest; + if(targ) + { + glScissor(0,0,targ->w,targ->h); + glViewport(0,0,targ->w,targ->h); + configProjectionMatrix2D(targ->w,targ->h); + } + else + { + glScissor(0,0,scrw,scrh); + glViewport(0,0,scrw,scrh); + configProjectionMatrix2D(scrw,scrh); + } + sm2DCamera5f3v(NULL,NULL,NULL); + curTarget=targ;tdmode=0; + vertexArray=vertexBuf; + return true; +} +bool SMELT_IMPL::smRenderBegin3D(float fov,bool ztest,SMTRG trg) +{ + TRenderTargetList *targ=(TRenderTargetList*)trg; + if(vertexArray) + {smLog("%s:" SLINE ": Last frame not closed.\n",GFX_GLFW_SRCFN);return false;} + glBindFramebuffer(GL_FRAMEBUFFER,(targ)?targ->frame:0); + glDepthFunc(GL_LESS); + ztest?glEnable(GL_DEPTH_TEST):glDisable(GL_DEPTH_TEST); + zbufenabled=ztest; + if(targ) + { + glScissor(0,0,targ->w,targ->h); + glViewport(0,0,targ->w,targ->h); + configProjectionMatrix3D(targ->w,targ->h,fov); + } + else + { + glScissor(0,0,scrw,scrh); + glViewport(0,0,scrw,scrh); + configProjectionMatrix3D(scrw,scrh,fov); + } + sm3DCamera6f2v(NULL,NULL); + curTarget=targ;tdmode=1; + vertexArray=vertexBuf; + return true; +} +bool SMELT_IMPL::smRenderEnd() +{ + batchOGL(true); + if(curTarget&&curTarget->ms) + { + glTexture *pTex=(glTexture*)curTarget->tex; + if(pTex&&pTex->lost) + configTexture(pTex,pTex->rw,pTex->rh,pTex->px); + int w=curTarget->w,h=curTarget->h; + glFinish(); + DWORD *px=new DWORD[w*h]; + glBindFramebuffer(GL_READ_FRAMEBUFFER,curTarget->frame); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER,curTarget->sframe); + glBlitFramebuffer(0,0,w,h,0,0,w,h,GL_COLOR_BUFFER_BIT,GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER,curTarget->sframe); + glReadPixels(0,0,w,h,GL_RGBA,GL_UNSIGNED_BYTE,px); + glBindTexture(GL_TEXTURE_2D,pTex->name); + glTexSubImage2D(GL_TEXTURE_2D,0,0,0,w,h,GL_RGBA,GL_UNSIGNED_BYTE,px); + glBindTexture(GL_TEXTURE_2D,primTex?(((glTexture*)primTex)->name):0); + delete[] px; + } + if(!curTarget)glfwSwapBuffers((GLFWwindow*)hwnd); + return true; +} +void SMELT_IMPL::smClrscr(DWORD color,bool clearcol,bool cleardep) +{ + GLfloat a=(GLfloat)(GETA(color))/255.f; + GLfloat r=(GLfloat)(GETR(color))/255.f; + GLfloat g=(GLfloat)(GETG(color))/255.f; + GLfloat b=(GLfloat)(GETB(color))/255.f; + if(clearcol) + glClearColor(r,g,b,a); + if(tdmode)glClearDepth(1); + else if(zbufenabled)glClearDepth(0); + glClear((clearcol?GL_COLOR_BUFFER_BIT:0)|(((zbufenabled||tdmode)&&cleardep)?GL_DEPTH_BUFFER_BIT:0)); +} +void SMELT_IMPL::sm3DCamera6f2v(float *pos,float *rot) +{ + batchOGL(); + smMatrix Mmodv; + Mmodv.loadIdentity(); + if(pos&&rot) + { + Mmodv.rotate(smMath::deg2rad(-rot[0]),1,0,0); + Mmodv.rotate(smMath::deg2rad(-rot[1]),0,1,0); + Mmodv.rotate(smMath::deg2rad(-rot[2]),0,0,1); + Mmodv.translate(-pos[0],-pos[1],-pos[2]); + } + memcpy(mmodv,Mmodv.m,sizeof(mmodv)); + glUniformMatrix4fv(loc_mmodv,1,0,mmodv); +} +void SMELT_IMPL::smMultViewMatrix(float *mat) +{ + smMatrix Mmodv(mmodv); + Mmodv=Mmodv*smMatrix(mat); + memcpy(mmodv,Mmodv.m,sizeof(mmodv)); +} +void SMELT_IMPL::sm2DCamera5f3v(float *pos,float *dpos,float *rot) +{ + batchOGL(); + smMatrix Mmodv; + Mmodv.loadIdentity(); + if(pos&&dpos&&rot) + { + Mmodv.translate(-pos[0],-pos[1],.0f); + Mmodv.rotate(*rot,.0f,.0f,1.0f); + Mmodv.translate(pos[0]+dpos[0],pos[1]+dpos[1],.0f); + } + memcpy(mmodv,Mmodv.m,sizeof(mmodv)); + glUniformMatrix4fv(loc_mmodv,1,0,mmodv); +} +void SMELT_IMPL::smRenderLinefd(float x1,float y1,float z1,float x2,float y2,float z2,DWORD color) +{ + if(vertexArray) + { + if(primType!=PRIM_LINES||primcnt>=VERTEX_BUFFER_SIZE/PRIM_LINES||primTex||primBlend!=BLEND_ALPHABLEND) + { + batchOGL(); + primType=PRIM_LINES; + if(primBlend!=BLEND_ALPHAADD)setBlend(BLEND_ALPHAADD); + bindTexture(NULL); + } + int i=(primcnt++)*PRIM_LINES; + vertexArray[i].x=x1,vertexArray[i+1].x=x2; + vertexArray[i].y=y1,vertexArray[i+1].y=y2; + vertexArray[i].x=z1,vertexArray[i+1].x=z2; + vertexArray[i].col=vertexArray[i+1].col=color; + vertexArray[i].tx=vertexArray[i+1].tx=.0; + vertexArray[i].ty=vertexArray[i+1].ty=.0; + } +} +void SMELT_IMPL::smRenderLinefvd(float *p1,float *p2,DWORD color) +{ + if(vertexArray&&p1&&p2) + { + if(primType!=PRIM_LINES||primcnt>=VERTEX_BUFFER_SIZE/PRIM_LINES||primTex||primBlend!=BLEND_ALPHABLEND) + { + batchOGL(); + primType=PRIM_LINES; + if(primBlend!=BLEND_ALPHAADD)setBlend(BLEND_ALPHAADD); + bindTexture(NULL); + } + int i=(primcnt++)*PRIM_LINES; + vertexArray[i].x=p1[0],vertexArray[i+1].x=p2[0]; + vertexArray[i].y=p1[1],vertexArray[i+1].y=p2[1]; + vertexArray[i].x=p2[2],vertexArray[i+1].x=p2[2]; + vertexArray[i].col=vertexArray[i+1].col=color; + vertexArray[i].tx=vertexArray[i+1].tx=.0; + vertexArray[i].ty=vertexArray[i+1].ty=.0; + } +} +void SMELT_IMPL::smRenderTriangle(smTriangle *t) +{ + if(vertexArray) + { + if(primType!=PRIM_TRIANGLES||primcnt>=VERTEX_BUFFER_SIZE/PRIM_TRIANGLES|| + primTex!=t->tex||primBlend!=t->blend) + { + batchOGL(); + primType=PRIM_TRIANGLES; + if(primBlend!=t->blend)setBlend(t->blend); + bindTexture((glTexture*)t->tex); + } + memcpy(&vertexArray[(primcnt++)*PRIM_TRIANGLES],t->v,sizeof(smVertex)*PRIM_TRIANGLES); + } +} +void SMELT_IMPL::smRenderQuad(smQuad *q) +{ + if(vertexArray) + { + if(primType!=PRIM_QUADS||primcnt>=VERTEX_BUFFER_SIZE/PRIM_QUADS|| + primTex!=q->tex||primBlend!=q->blend) + { + batchOGL(); + primType=PRIM_QUADS; + if(primBlend!=q->blend)setBlend(q->blend); + bindTexture((glTexture*)q->tex); + } + memcpy(&vertexArray[(primcnt++)*PRIM_QUADS],q->v,sizeof(smVertex)*PRIM_QUADS); + } +} +smVertex* SMELT_IMPL::smGetVertArray() +{ + if(vertexArray) + { + batchOGL(); + return vertexArray; + } + else return NULL; +} +void SMELT_IMPL::smDrawVertArray(int prim,SMTEX texture,int blend,int _primcnt) +{ + primType=prim; + bindTexture((glTexture*)texture); + if(primBlend!=blend)setBlend(blend); + primcnt=primcnt; +} +void SMELT_IMPL::smDrawCustomIndexedVertices(smVertex* vb,WORD* ib,int vbc,int ibc,int blend,SMTEX texture) +{ + if(vertexArray) + { + batchOGL(); + + float twm=1.,thm=1.; + if(texture) + { + glTexture *ptex=(glTexture*)texture; + if(ptex->dw&&ptex->dh) + { + twm=(ptex->rw)/(float)(ptex->dw); + thm=(ptex->rh)/(float)(ptex->dh); + } + } + if(!tdmode) + { + float h=curTarget?curTarget->h:scrh; + for(int i=0;i<vbc;++i) + { + vertexArray[i].y=h-vertexArray[i].y; + vertexArray[i].z=-vertexArray[i].z; + } + } + for(int i=0;i<vbc;++i) + { + vb[i].tx*=twm; + vb[i].ty=(1.-vb[i].ty)*thm; + DWORD color=vb[i].col; + BYTE *col=(BYTE*)&vb[i].col; + BYTE a=((color>>24)&0xFF); + BYTE r=((color>>16)&0xFF); + BYTE g=((color>> 8)&0xFF); + BYTE b=((color>> 0)&0xFF); + col[0]=r;col[1]=g; + col[2]=b;col[3]=a; + } + if(texture!=primTex)bindTexture((glTexture*)texture); + if(blend!=primBlend)setBlend(blend); + glBindVertexArray(VertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER,VertexBufferObject); + glBufferData(GL_ARRAY_BUFFER,sizeof(smVertex)*vbc,vb,GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,IndexBufferObject); + glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*ibc,ib,GL_STATIC_DRAW); + glDrawElements(GL_TRIANGLES,ibc,GL_UNSIGNED_SHORT,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,IndexBufferObject); + glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*((VERTEX_BUFFER_SIZE*6)/4),indexBuf,GL_STATIC_DRAW); + glBindVertexArray(0); + if(texture!=primTex)bindTexture((glTexture*)primTex); + + } +} +SMTRG SMELT_IMPL::smTargetCreate(int w,int h,int ms) +{ + bool ok=false; + TRenderTargetList *pTarget=new TRenderTargetList; + memset(pTarget,0,sizeof(TRenderTargetList)); + pTarget->tex=buildTexture(w,h,NULL); + glTexture *gltex=(glTexture*)pTarget->tex; + gltex->isTarget=true;gltex->lost=false; + configTexture(gltex,w,h,NULL,false); + pTarget->w=w;pTarget->h=h; + ok=buildTarget(pTarget,gltex->name,w,h,ms); + if(!ok) + { + smLog("%s:" SLINE ": Failed to create render target.\n",GFX_GLFW_SRCFN); + smTextureFree(pTarget->tex); + delete pTarget; + return 0; + } + pTarget->next=targets; + targets=pTarget; + return (SMTRG)pTarget; +} +SMTEX SMELT_IMPL::smTargetTexture(SMTRG targ) +{ + TRenderTargetList *pTarg=(TRenderTargetList*)targ; + return targ?pTarg->tex:0; +} +void SMELT_IMPL::smTargetFree(SMTRG targ) +{ + TRenderTargetList *pTarget=targets,*pLastTarg=NULL; + while(pTarget) + { + if((TRenderTargetList*)targ==pTarget) + { + if(pLastTarg)pLastTarg->next=pTarget->next; + else targets=pTarget->next; + if(curTarget==(TRenderTargetList*)targ) + glBindFramebuffer(GL_FRAMEBUFFER_EXT,0); + if(pTarget->depth) + glDeleteRenderbuffers(1,&pTarget->depth); + glDeleteFramebuffers(1,&pTarget->frame); + if(pTarget->ms) + { + glDeleteRenderbuffers(1,&pTarget->colorms); + glDeleteRenderbuffers(1,&pTarget->scolor); + glDeleteRenderbuffers(1,&pTarget->sdepth); + glDeleteFramebuffers(1,&pTarget->sframe); + } + if(curTarget==(TRenderTargetList*)targ)curTarget=0; + smTextureFree(pTarget->tex); + delete pTarget; + return; + } + pLastTarg=pTarget; + pTarget=pTarget->next; + } +} +SMTEX SMELT_IMPL::smTextureCreate(int w,int h) +{ + DWORD *px=new DWORD[w*h]; + memset(px,0,sizeof(DWORD)*w*h); + SMTEX ret=buildTexture(w,h,px); + if(ret) + { + TTextureList *tex=new TTextureList; + tex->tex=ret; + tex->w=w; + tex->h=h; + tex->next=textures; + textures=tex; + } + return ret; +} +SMTEX SMELT_IMPL::smTextureLoad(const char *path) +{ + FILE *pFile;DWORD size,rsize;char *buff; + SMTEX ret=0; + pFile=fopen(path,"rb"); + if(!pFile)return 0; + fseek(pFile,0,SEEK_END);size=ftell(pFile);rewind(pFile); + buff=(char*)malloc(sizeof(char)*size); + if(!buff)return 0; + rsize=fread(buff,1,size,pFile); + if(rsize!=size)return 0; + ret=smTextureLoadFromMemory(buff,size);if(!ret)return 0; + glTexture *t=(glTexture*)ret; + configTexture(t,t->rw,t->rh,t->px); + delete[] t->px;t->px=NULL; + t->fn=strcpy(new char[strlen(path)+1],path); + free(buff); + fclose(pFile); + return ret; +} +SMTEX SMELT_IMPL::smTextureLoadFromMemory(const char *ptr,DWORD size) +{ + int w=0,h=0;SMTEX ret=0; + DWORD *px=decodeImage((BYTE*)ptr,NULL,size,w,h); + if(px)ret=buildTexture(w,h,px); + if(ret) + { + TTextureList *tex=new TTextureList; + tex->tex=ret;tex->w=w;tex->h=h; + tex->next=textures;textures=tex; + }else smLog("%s:" SLINE ": Unsupported texture format.\n",GFX_GLFW_SRCFN); + return ret; +} +void SMELT_IMPL::smTextureFree(SMTEX tex) +{ + if(!pOpenGLDevice)return; + TTextureList *ctex=textures,*lasttex=NULL; + while(ctex) + { + if(ctex->tex==tex) + { + if(lasttex)lasttex->next=ctex->next; + else textures=ctex->next; + delete ctex; + break; + } + lasttex=ctex; + ctex=ctex->next; + } + if(tex) + { + glTexture *ptex=(glTexture*)tex; + delete[] ptex->fn; + delete[] ptex->locpx; + delete[] ptex->px; + glDeleteTextures(1,&ptex->name); + delete ptex; + } +} +void SMELT_IMPL::smTextureOpt(int potopt,int filter) +{ + batchOGL(); + if(potopt==TPOT_NONPOT) + { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE); + } + if(potopt==TPOT_POT) + { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_R,GL_REPEAT); + } + filtermode=filter; + if(filter==TFLT_NEAREST) + { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + } + if(filter==TFLT_LINEAR) + { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + } +} +int SMELT_IMPL::smTextureGetWidth(SMTEX tex,bool original) +{ + if(original) + { + TTextureList *ctex=textures; + while(ctex){if(ctex->tex==tex)return ctex->w;ctex=ctex->next;} + } + else return ((glTexture*)tex)->rw; + return 0; +} +int SMELT_IMPL::smTextureGetHeight(SMTEX tex,bool original) +{ + if(original) + { + TTextureList *ctex=textures; + while(ctex){if(ctex->tex==tex)return ctex->h;ctex=ctex->next;} + } + else return ((glTexture*)tex)->rh; + return 0; +} +DWORD* SMELT_IMPL::smTextureLock(SMTEX tex,int l,int t,int w,int h,bool ro) +{ + glTexture *ptex=(glTexture*)tex; + if(ptex->locpx)return NULL; + bool fromfile=(ptex->px==NULL&&ptex->fn); + if(fromfile) + { + FILE *pFile;DWORD size,rsize;char *buff; + pFile=fopen(ptex->fn,"rb"); + if(!pFile)return 0; + fseek(pFile,0,SEEK_END);size=ftell(pFile);rewind(pFile); + buff=(char*)malloc(sizeof(char)*size); + if(!buff)return 0; + rsize=fread(buff,1,size,pFile); + if(rsize!=size)return 0; + int _w,_h; + ptex->px=decodeImage((BYTE*)buff,ptex->fn,size,_w,_h); + if(_w!=(int)ptex->rw||_h!=(int)ptex->rh) + {delete[] ptex->px;ptex->px=NULL;} + free(buff); + fclose(pFile); + if(ptex->px&&!ro){delete[] ptex->fn;ptex->fn=NULL;} + } + if(!ptex->px&&!ptex->isTarget)return 0; + if(!w)w=ptex->rw;if(!h)h=ptex->rh; + //asserts... + ptex->roloc=ro;ptex->locx=l;ptex->locy=t;ptex->locw=w;ptex->loch=h; + ptex->locpx=new DWORD[w*h]; + if(!ptex->isTarget) + { + DWORD *dst=ptex->locpx,*src=ptex->px+((t*ptex->rw)+l); + for(int i=0;i<h;++i)//TODO: flip it... + { + memcpy(dst,src,w*sizeof(DWORD)); + dst+=w;src+=ptex->rw; + } + } + else return 0; + return ptex->locpx; +} +void SMELT_IMPL::smTexutreUnlock(SMTEX tex) +{ + glTexture *ptex=(glTexture*)tex; + if(!ptex->locpx)return; + if(!ptex->roloc) + { + DWORD *src=ptex->locpx+ptex->locw*ptex->loch, + *dst=ptex->px+(((ptex->rh-ptex->locy-1)*ptex->rw)+ptex->locx); + for(int i=0;i<ptex->loch;++i) + { + memcpy(dst,src,ptex->locw*sizeof(DWORD)); + dst-=ptex->rw;src-=ptex->locw; + } + if(ptex->lost)configTexture(ptex,ptex->rw,ptex->rh,ptex->px); + else + { + glBindTexture(GL_TEXTURE_2D,ptex->name); + glTexSubImage2D(GL_TEXTURE_2D,0,ptex->locx, + (ptex->rh-ptex->locy)-ptex->loch,ptex->locw,ptex->loch,GL_RGBA, + GL_UNSIGNED_BYTE,ptex->locpx); + glBindTexture(GL_TEXTURE_2D,primTex?(((glTexture*)primTex)->name):0); + } + } + if(ptex->fn&&ptex->roloc){delete[] ptex->px;ptex->px=NULL;} + delete[] ptex->locpx;ptex->locpx=NULL; + ptex->roloc=false; + ptex->locx=ptex->locy=ptex->locw=ptex->loch=-1; +} + +inline bool ispot(GLuint x){return((x&(x-1))==0);} +inline GLuint npot(GLuint x) +{ + --x; + for(unsigned i=1;i<sizeof(GLuint)*8;i<<=1)x|=x>>i; + return x+1; +} +DWORD* SMELT_IMPL::decodeImage(BYTE *data,const char *fn,DWORD size,int &w,int &h) +{ + w=h=0; + DWORD *px=NULL; + int fnlen=fn?strlen(fn):0; + if((fnlen>5)&&(strcasecmp((fn+fnlen)-5,".rgba"))==0)//raw image... pending remove + { + DWORD *ptr=(DWORD*)data; + DWORD _w=ptr[0],_h=ptr[1]; + if(((_w*_h*4)+8)==size) + { + w=_w;h=_h; + px=new DWORD[w*h]; + memcpy(px,ptr+2,w*h*4); + } + return px; + } + CxImage img; + img.Decode(data,size,CXIMAGE_FORMAT_UNKNOWN); + if(img.IsValid()) + { + w=img.GetWidth();h=img.GetHeight(); + px=new DWORD[w*h]; + BYTE *sptr=(BYTE*)px; + bool atunnel=img.AlphaIsValid(); + for(int i=0;i<h;++i) + for(int j=0;j<w;++j) + { + RGBQUAD rgb=img.GetPixelColor(j,i,true); + *(sptr++)=rgb.rgbRed; + *(sptr++)=rgb.rgbGreen; + *(sptr++)=rgb.rgbBlue; + *(sptr++)=atunnel?rgb.rgbReserved:0xFF; + } + } + return px; +} +void SMELT_IMPL::bindTexture(glTexture *t) +{ + if(t&&t->lost) + configTexture(t,t->rw,t->rh,t->px); + if(((SMTEX)t)!=primTex) + { + glBindTexture(GL_TEXTURE_2D,t?t->name:((glTexture*)emptyTex)->name); + glUniform1i(loc_tex,0); + primTex=(SMTEX)t; + } +} +bool SMELT_IMPL::buildTarget(TRenderTargetList *pTarget,GLuint texid,int w,int h,int ms=0) +{ + bool ok=true; + if(ms) + { + glGenFramebuffers(1,&pTarget->sframe); + glBindFramebuffer(GL_FRAMEBUFFER,pTarget->sframe); + glGenRenderbuffers(1,&pTarget->scolor); + glBindRenderbuffer(GL_RENDERBUFFER,pTarget->scolor); + glRenderbufferStorage(GL_RENDERBUFFER,GL_RGBA,w,h); + glGenRenderbuffers(1,&pTarget->sdepth); + glBindRenderbuffer(GL_RENDERBUFFER,pTarget->sdepth); + glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT24,w,h); + glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,pTarget->scolor); + glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,pTarget->sdepth); + + glGenFramebuffers(1,&pTarget->frame); + glBindFramebuffer(GL_FRAMEBUFFER,pTarget->frame); + glGenRenderbuffers(1,&pTarget->colorms); + glBindRenderbuffer(GL_RENDERBUFFER,pTarget->colorms); + glRenderbufferStorageMultisample(GL_RENDERBUFFER,ms,GL_RGBA,w,h); + glGenRenderbuffers(1,&pTarget->depth); + glBindRenderbuffer(GL_RENDERBUFFER,pTarget->depth); + glRenderbufferStorageMultisample(GL_RENDERBUFFER,ms,GL_DEPTH_COMPONENT24,w,h); + glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,pTarget->colorms); + glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,pTarget->depth); + GLenum rc=glCheckFramebufferStatus(GL_FRAMEBUFFER); + if((rc==GL_FRAMEBUFFER_COMPLETE)&&(glGetError()==GL_NO_ERROR)) + { + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + ok=true;pTarget->ms=ms; + } + else + { + glBindFramebuffer(GL_FRAMEBUFFER,0); + glDeleteRenderbuffers(1,&pTarget->colorms); + glDeleteRenderbuffers(1,&pTarget->depth); + glDeleteFramebuffers(1,&pTarget->frame); + glDeleteFramebuffers(1,&pTarget->sframe); + ok=false;ms=0; + } + glBindFramebuffer(GL_FRAMEBUFFER,curTarget?curTarget->frame:0); + } + if(!ms) + { + glGenFramebuffers(1,&pTarget->frame); + glGenRenderbuffers(1,&pTarget->depth); + glBindFramebuffer(GL_FRAMEBUFFER,pTarget->frame); + glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,texid,0); + glBindRenderbuffer(GL_RENDERBUFFER,pTarget->depth); + glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT24,w,h); + glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,pTarget->depth); + GLenum rc=glCheckFramebufferStatus(GL_FRAMEBUFFER); + if((rc==GL_FRAMEBUFFER_COMPLETE)&&(glGetError()==GL_NO_ERROR)) + { + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + ok=true;pTarget->ms=0; + } + else + { + glBindFramebuffer(GL_FRAMEBUFFER,0); + glDeleteRenderbuffers(1,&pTarget->depth); + glDeleteFramebuffers(1,&pTarget->frame); + ok=false; + } + glBindFramebuffer(GL_FRAMEBUFFER,curTarget?curTarget->frame:0); + } + return ok; +} +void SMELT_IMPL::configTexture(glTexture *t,int w,int h,DWORD *px,bool compressed) +{ + GLuint tex=0; + glGenTextures(1,&tex); + t->lost=false;t->name=tex;t->rw=w;t->rh=h;t->px=px; + t->dw=t->dh=0; + bool fromfile=(!px&&(t->fn)); + if(fromfile) + { + FILE *pFile;DWORD size,rsize;char *buff; + pFile=fopen(t->fn,"rb"); + if(!pFile)return; + fseek(pFile,0,SEEK_END);size=ftell(pFile);rewind(pFile); + buff=(char*)malloc(sizeof(char)*size); + if(!buff)return; + rsize=fread(buff,1,size,pFile); + if(rsize!=size)return; + int _w,_h; + px=decodeImage((BYTE*)buff,t->fn,size,_w,_h); + if(_w!=w||_h!=h){delete[] px;px=NULL;} + free(buff); + fclose(pFile); + } + glBindTexture(GL_TEXTURE_2D,tex); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_LOD,0.0f); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAX_LOD,0.0f); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_BASE_LEVEL,0); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL,0); + compressed=false;//compression is unusable at this moment + const GLenum fmt=compressed?/*GL_COMPRESSED_RGBA_S3TC_DXT5_EXT*/GL_COMPRESSED_RGBA_ARB:GL_RGBA8; + glTexImage2D(GL_TEXTURE_2D,0,fmt,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,px); + glBindTexture(GL_TEXTURE_2D,primTex?(((glTexture*)primTex)->name):0); + if(fromfile)delete[] px; +} +SMTEX SMELT_IMPL::buildTexture(int w,int h,DWORD *px) +{ + glTexture *ret=new glTexture; + memset(ret,0,sizeof(glTexture)); + ret->lost=true; + ret->rw=w;ret->rh=h;ret->px=px; + return (SMTEX)ret; +} +void SMELT_IMPL::configProjectionMatrix2D(int w,int h) +{ + memset(mproj,0,sizeof(mproj)); + mproj[0]=2./w; + mproj[5]=2./h; + mproj[10]=-2.; + mproj[15]=1.; + mproj[12]=mproj[13]=mproj[14]=-1.; + glUniformMatrix4fv(loc_mproj,1,0,mproj); +} +void SMELT_IMPL::configProjectionMatrix3D(int w,int h,float fov) +{ + memset(mproj,0,sizeof(mproj)); + float f=1./tanf(M_PI*fov/360.); + float ar=(float)w/(float)h; + float Near=0.1,Far=1000.; + mproj[0]=f/ar;mproj[5]=f; + mproj[10]=(Far+Near)/(Near-Far);mproj[11]=-1.0f; + mproj[14]=(2*Far*Near)/(Near-Far); + glUniformMatrix4fv(loc_mproj,1,0,mproj); +} +void SMELT_IMPL::batchOGL(bool endScene) +{ + if(vertexArray&&primcnt) + { + float twm=1.,thm=1.; + if(primTex) + { + glTexture *ptex=(glTexture*)primTex; + if(ptex->dw&&ptex->dh) + { + twm=(ptex->rw)/(float)(ptex->dw); + thm=(ptex->rh)/(float)(ptex->dh); + } + } + if(!tdmode) + { + float h=curTarget?curTarget->h:scrh; + for(int i=0;i<primcnt*primType;++i) + { + vertexArray[i].y=h-vertexArray[i].y; + vertexArray[i].z=-vertexArray[i].z; + } + } + for(int i=0;i<primcnt*primType;++i) + { + vertexArray[i].tx*=twm; + vertexArray[i].ty*=thm; + DWORD color=vertexArray[i].col; + BYTE *col=(BYTE*)&vertexArray[i].col; + BYTE a=((color>>24)&0xFF); + BYTE r=((color>>16)&0xFF); + BYTE g=((color>> 8)&0xFF); + BYTE b=((color>> 0)&0xFF); + col[0]=r;col[1]=g; + col[2]=b;col[3]=a; + } + glBindVertexArray(VertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER,VertexBufferObject); + glBufferData(GL_ARRAY_BUFFER,sizeof(smVertex)*primcnt*primType,vertexBuf,GL_STATIC_DRAW); + switch(primType) + { + case PRIM_LINES: + glDrawArrays(GL_LINES,0,2*primcnt); + break; + case PRIM_TRIANGLES: + glDrawArrays(GL_TRIANGLES,0,3*primcnt); + break; + case PRIM_QUADS: + glDrawElements(GL_TRIANGLES,6*primcnt,GL_UNSIGNED_SHORT,0); +#if 0 + for (int i=0;i<primcnt*6;i+=3) + { + printf("idxbuf:%d\n",indexBuf[i]); + printf("QUAD'S TRIANGLE:\n"); +#define printVertex(a) printf("(%.2f,%.2f,%.2f),0x%X,(%.2f,%.2f)\n",a.x,a.y,a.z,a.col,a.tx,a.ty); + printf("#%d: ",indexBuf[i+0]);printVertex(vertexBuf[indexBuf[i+0]]); + printf("#%d: ",indexBuf[i+1]);printVertex(vertexBuf[indexBuf[i+1]]); + printf("#%d: ",indexBuf[i+2]);printVertex(vertexBuf[indexBuf[i+2]]); +#undef printVertex + } +#endif + break; + } + glBindVertexArray(0); + primcnt=0; + } + if(vertexArray)vertexArray=endScene?0:vertexBuf; +} +void SMELT_IMPL::setBlend(int blend) +{ + if((blend&BLEND_ALPHABLEND)!=(primBlend&BLEND_ALPHABLEND)) + { + if(blend&BLEND_ALPHABLEND)glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + else glBlendFunc(blend&BLEND_COLORINV?GL_ONE_MINUS_DST_COLOR:GL_SRC_ALPHA,blend&BLEND_COLORINV?GL_ZERO:GL_ONE); + } + if((blend&BLEND_ZWRITE)!=(primBlend&BLEND_ZWRITE)) + { + if(blend&BLEND_ZWRITE||tdmode)glDepthMask(GL_TRUE); + else glDepthMask(GL_FALSE); + } + if((blend&BLEND_COLORADD)!=(primBlend&BLEND_COLORADD)) + { + if(blend&BLEND_COLORADD)glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_ADD); + else glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); + } + if((blend&BLEND_COLORINV)!=(primBlend&BLEND_COLORINV)) + { + if(blend&BLEND_COLORINV)glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO); + else glBlendFunc(GL_SRC_ALPHA,blend&BLEND_ALPHABLEND?GL_ONE_MINUS_SRC_ALPHA:GL_ONE); + } + primBlend=blend; +} +void SMELT_IMPL::unloadGLEntryPoints() +{ +} +bool SMELT_IMPL::checkGLExtension(const char *extlist,const char *ext) +{ + return true;/*shit* + const char *ptr=strstr(extlist,ext); + if(ptr==NULL)return false; + const char endchar=ptr[strlen(ext)]; + if((endchar=='\0')||(endchar==' '))return true; + return false;*/ +} +bool SMELT_IMPL::loadGLEntryPoints() +{ + smLog("%s:" SLINE ": Initializing with OpenGL core profile...\n",GFX_GLFW_SRCFN); + pOpenGLDevice->have_base_opengl=true; + /* + * All OpenGL features utilized by SMELT are in the core profile + * for OpenGL >= 3.2. So this function is essentially useless. + */ + glewExperimental=true; + GLenum glewret=glewInit(); + if(glewret) + { + smLog("%s:" SLINE ": glewInit() failed with error %s\n",GFX_GLFW_SRCFN,glewGetErrorString(glewret)); + pOpenGLDevice->have_base_opengl=false; + return false; + } + if (!pOpenGLDevice->have_base_opengl) + { + unloadGLEntryPoints(); + return false; + } + smLog("%s:" SLINE ": GL_RENDERER: %s\n",GFX_GLFW_SRCFN,(const char *)glGetString(GL_RENDERER)); + smLog("%s:" SLINE ": GL_VENDOR: %s\n",GFX_GLFW_SRCFN,(const char *)glGetString(GL_VENDOR)); + smLog("%s:" SLINE ": GL_VERSION: %s\n",GFX_GLFW_SRCFN,(const char *)glGetString(GL_VERSION)); + const char *verstr=(const char*)glGetString(GL_VERSION); + int maj=0,min=0; + sscanf(verstr,"%d.%d",&maj,&min); + if((maj<3)||((maj==3)&&(min<2))) + { + smLog("%s:" SLINE ": OpenGL implementation must be at least version 3.2.\n",GFX_GLFW_SRCFN); + unloadGLEntryPoints(); + return false; + } + return true; +} +bool SMELT_IMPL::initOGL() +{ + primTex=0;emptyTex=0; + if(pOpenGLDevice){smLog("%s:" SLINE ": Multiple initialization!\n",GFX_GLFW_SRCFN);return false;} + pOpenGLDevice=new TOpenGLDevice; + if(!loadGLEntryPoints())return false; + smLog("%s:" SLINE ": Mode: %d x %d\n",GFX_GLFW_SRCFN,scrw,scrh); + vertexArray=NULL;textures=NULL; + ShaderProgram=vertshader=fragshader=0; + VertexBufferObject=VertexArrayObject=IndexBufferObject=0; + if(!confOGL())return false; + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + if(!curTarget)glfwSwapBuffers((GLFWwindow*)hwnd); + return true; +} +void SMELT_IMPL::finiOGL() +{ + while(textures)smTextureFree(textures->tex); + while(targets)smTargetFree((SMTRG)targets); + textures=NULL;targets=NULL;vertexArray=NULL; + delete[] vertexBuf;vertexBuf=NULL; + delete[] indexBuf;indexBuf=NULL; + if(pOpenGLDevice) + { + if(1) + { + if(VertexBufferObject!=0) + { + glBindVertexArray(VertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + glDeleteBuffers(1,&VertexBufferObject); + glDeleteBuffers(1,&IndexBufferObject); + glBindVertexArray(0); + glDeleteVertexArrays(1,&VertexArrayObject); + VertexArrayObject=0; + VertexBufferObject=0; + IndexBufferObject=0; + } + } + glDeleteProgram(ShaderProgram); + delete pOpenGLDevice; + pOpenGLDevice=NULL; + } +} +bool SMELT_IMPL::restOGL() +{ + if(!pOpenGLDevice)return false; + delete[] vertexBuf;vertexBuf=NULL; + delete[] indexBuf;indexBuf=NULL; + unloadGLEntryPoints(); + if(!loadGLEntryPoints())return false; + if(!confOGL())return false; + //if()return();//TODO: rest func + return true; +} +bool SMELT_IMPL::confOGL() +{ + bindTexture(NULL); + DWORD ones=~0U; + if(!emptyTex) + {emptyTex=buildTexture(1,1,&ones);} + configTexture((glTexture*)emptyTex,1,1,&ones,false); + for(TTextureList *i=textures;i;i=i->next) + { + glTexture *t=(glTexture*)i->tex; + if(!t)continue;t->lost=true;t->name=0; + } + TRenderTargetList *target=targets; + while(target) + { + glTexture *tex=(glTexture*)target->tex; + bindTexture(tex);bindTexture(NULL); + buildTarget(target,tex?tex->name:0,target->w,target->h); + target=target->next; + } + int compret=0; + ShaderProgram=glCreateProgram(); + vertshader=glCreateShader(GL_VERTEX_SHADER); + fragshader=glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(vertshader,1,&fixedfunc_pipeline_vsh,NULL); + glShaderSource(fragshader,1,&fixedfunc_pipeline_fsh,NULL); + glCompileShader(vertshader); + glGetShaderiv(vertshader,GL_COMPILE_STATUS,&compret); + //char log[1024]; + //glGetShaderInfoLog(vertshader,1024,NULL,log); + //puts(log); + if(!compret) + smLog("%s:" SLINE ": Warning: Your shitty vertex shader failed to compile!\n",GFX_GLFW_SRCFN); + glCompileShader(fragshader); + glGetShaderiv(fragshader,GL_COMPILE_STATUS,&compret); + //glGetShaderInfoLog(fragshader,1024,NULL,log); + //puts(log); + if(!compret) + smLog("%s:" SLINE ": Warning: Your shitty fragment shader failed to compile!\n",GFX_GLFW_SRCFN); + glAttachShader(ShaderProgram,vertshader); + glAttachShader(ShaderProgram,fragshader); + glLinkProgram(ShaderProgram); + //glGetProgramInfoLog(ShaderProgram,1024,NULL,log); + //puts(log); + glGetProgramiv(ShaderProgram,GL_LINK_STATUS,&compret); + if(!compret) + smLog("%s:" SLINE ": Warning: Default shader linkage failure!\n",GFX_GLFW_SRCFN); + glDeleteShader(vertshader); + glDeleteShader(fragshader); + glUseProgram(ShaderProgram); + loc_tex=glGetUniformLocation(ShaderProgram,"tex"); + loc_mmodv=glGetUniformLocation(ShaderProgram,"mmodv"); + loc_mproj=glGetUniformLocation(ShaderProgram,"mproj"); + vertexBuf=new smVertex[VERTEX_BUFFER_SIZE]; + indexBuf=new GLushort[VERTEX_BUFFER_SIZE*6/4]; + GLushort* indices=indexBuf; + for(int i=0,n=0;i<VERTEX_BUFFER_SIZE/4;++i) + { + *indices++=n;*indices++=n+1; + *indices++=n+2;*indices++=n+2; + *indices++=n+3;*indices++=n; + n+=4; + } + glGenBuffers(1,&VertexBufferObject); + glGenVertexArrays(1,&VertexArrayObject); + glGenBuffers(1,&IndexBufferObject); + glBindVertexArray(VertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER,VertexBufferObject); + glBufferData(GL_ARRAY_BUFFER,sizeof(smVertex)*VERTEX_BUFFER_SIZE,vertexBuf,GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,IndexBufferObject); + glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*((VERTEX_BUFFER_SIZE*6)/4),indexBuf,GL_STATIC_DRAW); + glVertexAttribPointer(0,3,GL_FLOAT,0,sizeof(smVertex),(void*)offsetof(smVertex,x));//vp + glVertexAttribPointer(1,4,GL_UNSIGNED_BYTE,1,sizeof(smVertex),(void*)offsetof(smVertex,col));//vc + glVertexAttribPointer(2,2,GL_FLOAT,0,sizeof(smVertex),(void*)offsetof(smVertex,tx));//vtc + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + glBindVertexArray(0); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + glPixelStorei(GL_PACK_ALIGNMENT,1); + glEnable(GL_SCISSOR_TEST); + glDisable(GL_CULL_FACE); + glActiveTexture(GL_TEXTURE0); + glDepthFunc(GL_GEQUAL); + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + filtermode=TFLT_LINEAR; + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + //GL_REPEAT doesn't work with non-pot textures... + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE); + primcnt=0;primType=PRIM_QUADS;primBlend=BLEND_ALPHABLEND;primTex=0; + glScissor(0,0,scrw,scrh); + glViewport(0,0,scrw,scrh); + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + configProjectionMatrix2D(scrw,scrh); + smMatrix Mmodv;Mmodv.loadIdentity(); + memcpy(mmodv,Mmodv.m,sizeof(mmodv)); + glUniformMatrix4fv(loc_mmodv,1,0,mmodv); + return true; +} diff --git a/smelt/glfw_m/inp_glfw.cpp b/smelt/glfw_m/inp_glfw.cpp new file mode 100644 index 0000000..4bbd43e --- /dev/null +++ b/smelt/glfw_m/inp_glfw.cpp @@ -0,0 +1,204 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * Input manager implementation + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * + */ +#include "smelt_internal.hpp" +//static const char* INP_GLFW_SRCFN="smelt/glfw/inp_glfw.cpp"; +bool SMELT_IMPL::smGetInpEvent(smInpEvent *e) +{ + TInputEventList *eptr; + if(inpQueue) + { + eptr=inpQueue;memcpy(e,&eptr->e,sizeof(smInpEvent)); + inpQueue=inpQueue->next;delete eptr;return true; + } + return false; +} +void SMELT_IMPL::smGetMouse2f(float *x,float *y){*x=posx,*y=posy;} +void SMELT_IMPL::smSetMouse2f(float x,float y){glfwSetInputMode((GLFWwindow*)hwnd,x,y);} +void SMELT_IMPL::smSetMouseGrab(bool enabled){glfwSetInputMode((GLFWwindow*)hwnd,GLFW_CURSOR,enabled?GLFW_CURSOR_DISABLED:GLFW_CURSOR_NORMAL);} +int SMELT_IMPL::smGetWheel(){return posz;} +bool SMELT_IMPL::smIsMouseOver(){return mouseOver;} +int SMELT_IMPL::smGetKey(){return lkey;} +int SMELT_IMPL::smGetKeyState(int key) +{ + if(!(keyz[key]&4)&&keylst[key])return SMKST_RELEASE; + if(!(keyz[key]&4))return SMKST_NONE; + if((keyz[key]&4)&&!keylst[key])return SMKST_HIT; + return SMKST_KEEP; +} + +void SMELT_IMPL::buildEvent(int type,int k,int scan,int flags,int x,int y) +{ + TInputEventList *last,*eptr=new TInputEventList; + eptr->e.type=type;eptr->e.chcode=0; + int ptx=x,pty=y; + if(type==INPUT_KEYDOWN) + { + k=GLFWKeyToSMKey(k); + if((k<0)||(k>(int)(sizeof(keyz)/sizeof(keyz[0]))))return; + keyz[k]|=4;if(!(flags&SMINP_REPEAT))keyz[k]|=1; + eptr->e.chcode=(k>=32&&k<=127)?k:0; + } + if(type==INPUT_KEYUP) + { + k=GLFWKeyToSMKey(k); + if((k<0)||(k>(int)(sizeof(keyz)/sizeof(keyz[0]))))return; + keyz[k]&=~4;keyz[k]|=2; + eptr->e.chcode=(k>=32&&k<=127)?k:0; + } + if(type==INPUT_MOUSEWHEEL) + {eptr->e.sccode=0;eptr->e.wheel=k;} + else{eptr->e.sccode=k;eptr->e.wheel=0;} + if(type==INPUT_MBUTTONDOWN){keyz[k]|=1|4;captured=true;} + if(type==INPUT_MBUTTONUP){keyz[k]|=2;keyz[k]&=~4;ptx=(int)posx;pty=(int)posy;captured=false;} + if(keymods&GLFW_MOD_SHIFT)flags|=SMINP_SHIFT; + if(keymods&GLFW_MOD_CONTROL)flags|=SMINP_CTRL; + if(keymods&GLFW_MOD_ALT)flags|=SMINP_ALT; + //if(keymods&KMOD_CAPS)flags|=SMINP_CAPSLOCK; + //if(keymods&KMOD_MODE)flags|=SMINP_SCROLLLOCK; + //if(keymods&KMOD_NUM)flags|=SMINP_NUMLOCK; + eptr->e.flag=flags; + if(ptx==-1){eptr->e.x=posx;eptr->e.y=posy;} + else + { + ptx<0?ptx=0:0;pty<0?pty=0:0; + ptx>=scrw?ptx=scrw-1:0;pty>=scrh?pty=scrh-1:0; + eptr->e.x=(float)ptx;eptr->e.y=(float)pty; + } + eptr->next=0; + if(!inpQueue)inpQueue=eptr; + else + { + last=inpQueue; + while(last->next)last=last->next; + last->next=eptr; + } + if(eptr->e.type==INPUT_KEYDOWN||eptr->e.type==INPUT_MBUTTONDOWN) + lkey=eptr->e.sccode; + if(eptr->e.type==INPUT_MOUSEMOVE)posx=eptr->e.x,posy=eptr->e.y; + if(eptr->e.type==INPUT_MOUSEWHEEL)posz=eptr->e.wheel; +} +void SMELT_IMPL::initInput(){posx=posy=.0;memset(keyz,0,sizeof(keyz));} +void SMELT_IMPL::clearQueue() +{ + TInputEventList *nxt,*eptr=inpQueue; + for(unsigned i=0;i<sizeof(keyz)/sizeof(keyz[0]);++i)keyz[i]&=~3; + while(eptr){nxt=eptr->next;delete eptr;eptr=nxt;} + inpQueue=NULL;posz=0;lkey=0; +} +int SMELT_IMPL::GLFWKeyToSMKey(int glfwkey) +{ + switch (glfwkey) + { + case GLFW_KEY_ESCAPE: return SMK_ESCAPE; + case GLFW_KEY_BACKSPACE: return SMK_BACKSPACE; + case GLFW_KEY_TAB: return SMK_TAB; + case GLFW_KEY_ENTER: return SMK_ENTER; + case GLFW_KEY_SPACE: return SMK_SPACE; + case GLFW_KEY_LEFT_SHIFT: return SMK_SHIFT; + case GLFW_KEY_RIGHT_SHIFT: return SMK_SHIFT; + case GLFW_KEY_LEFT_CONTROL: return SMK_CTRL; + case GLFW_KEY_RIGHT_CONTROL: return SMK_CTRL; + case GLFW_KEY_LEFT_ALT: return SMK_ALT; + case GLFW_KEY_RIGHT_ALT: return SMK_ALT; + case GLFW_KEY_LEFT_SUPER: return SMK_LWIN; + case GLFW_KEY_RIGHT_SUPER: return SMK_RWIN; + case GLFW_KEY_PAUSE: return SMK_PAUSE; + case GLFW_KEY_CAPS_LOCK: return SMK_CAPSLOCK; + case GLFW_KEY_NUM_LOCK: return SMK_NUMLOCK; + case GLFW_KEY_SCROLL_LOCK: return SMK_SCROLLLOCK; + case GLFW_KEY_PAGE_UP: return SMK_PGUP; + case GLFW_KEY_PAGE_DOWN: return SMK_PGDN; + case GLFW_KEY_HOME: return SMK_HOME; + case GLFW_KEY_END: return SMK_END; + case GLFW_KEY_INSERT: return SMK_INSERT; + case GLFW_KEY_DELETE: return SMK_DELETE; + case GLFW_KEY_LEFT: return SMK_LEFT; + case GLFW_KEY_UP: return SMK_UP; + case GLFW_KEY_RIGHT: return SMK_RIGHT; + case GLFW_KEY_DOWN: return SMK_DOWN; + case GLFW_KEY_0: return SMK_0; + case GLFW_KEY_1: return SMK_1; + case GLFW_KEY_2: return SMK_2; + case GLFW_KEY_3: return SMK_3; + case GLFW_KEY_4: return SMK_4; + case GLFW_KEY_5: return SMK_5; + case GLFW_KEY_6: return SMK_6; + case GLFW_KEY_7: return SMK_7; + case GLFW_KEY_8: return SMK_8; + case GLFW_KEY_9: return SMK_9; + case GLFW_KEY_A: return SMK_A; + case GLFW_KEY_B: return SMK_B; + case GLFW_KEY_C: return SMK_C; + case GLFW_KEY_D: return SMK_D; + case GLFW_KEY_E: return SMK_E; + case GLFW_KEY_F: return SMK_F; + case GLFW_KEY_G: return SMK_G; + case GLFW_KEY_H: return SMK_H; + case GLFW_KEY_I: return SMK_I; + case GLFW_KEY_J: return SMK_J; + case GLFW_KEY_K: return SMK_K; + case GLFW_KEY_L: return SMK_L; + case GLFW_KEY_M: return SMK_M; + case GLFW_KEY_N: return SMK_N; + case GLFW_KEY_O: return SMK_O; + case GLFW_KEY_P: return SMK_P; + case GLFW_KEY_Q: return SMK_Q; + case GLFW_KEY_R: return SMK_R; + case GLFW_KEY_S: return SMK_S; + case GLFW_KEY_T: return SMK_T; + case GLFW_KEY_U: return SMK_U; + case GLFW_KEY_V: return SMK_V; + case GLFW_KEY_W: return SMK_W; + case GLFW_KEY_X: return SMK_X; + case GLFW_KEY_Y: return SMK_Y; + case GLFW_KEY_Z: return SMK_Z; + case GLFW_KEY_MINUS: return SMK_MINUS; + case GLFW_KEY_EQUAL: return SMK_EQUALS; + case GLFW_KEY_BACKSLASH: return SMK_BACKSLASH; + case GLFW_KEY_LEFT_BRACKET: return SMK_LBRACKET; + case GLFW_KEY_RIGHT_BRACKET: return SMK_RBRACKET; + case GLFW_KEY_SEMICOLON: return SMK_SEMICOLON; + case GLFW_KEY_APOSTROPHE: return SMK_APOSTROPHE; + case GLFW_KEY_COMMA: return SMK_COMMA; + case GLFW_KEY_PERIOD: return SMK_PERIOD; + case GLFW_KEY_SLASH: return SMK_SLASH; + case GLFW_KEY_KP_0: return SMK_NUMPAD0; + case GLFW_KEY_KP_1: return SMK_NUMPAD1; + case GLFW_KEY_KP_2: return SMK_NUMPAD2; + case GLFW_KEY_KP_3: return SMK_NUMPAD3; + case GLFW_KEY_KP_4: return SMK_NUMPAD4; + case GLFW_KEY_KP_5: return SMK_NUMPAD5; + case GLFW_KEY_KP_6: return SMK_NUMPAD6; + case GLFW_KEY_KP_7: return SMK_NUMPAD7; + case GLFW_KEY_KP_8: return SMK_NUMPAD8; + case GLFW_KEY_KP_9: return SMK_NUMPAD9; + case GLFW_KEY_KP_MULTIPLY: return SMK_MULTIPLY; + case GLFW_KEY_KP_DIVIDE: return SMK_DIVIDE; + case GLFW_KEY_KP_ADD: return SMK_ADD; + case GLFW_KEY_KP_SUBTRACT: return SMK_SUBTRACT; + case GLFW_KEY_KP_DECIMAL: return SMK_DECIMAL; + case GLFW_KEY_KP_ENTER:return SMK_ENTER; + case GLFW_KEY_F1: return SMK_F1; + case GLFW_KEY_F2: return SMK_F2; + case GLFW_KEY_F3: return SMK_F3; + case GLFW_KEY_F4: return SMK_F4; + case GLFW_KEY_F5: return SMK_F5; + case GLFW_KEY_F6: return SMK_F6; + case GLFW_KEY_F7: return SMK_F7; + case GLFW_KEY_F8: return SMK_F8; + case GLFW_KEY_F9: return SMK_F9; + case GLFW_KEY_F10: return SMK_F10; + case GLFW_KEY_F11: return SMK_F11; + case GLFW_KEY_F12: return SMK_F12; + default: return -1; + } + return -1; +} diff --git a/smelt/glfw_m/makefile b/smelt/glfw_m/makefile new file mode 100644 index 0000000..d487454 --- /dev/null +++ b/smelt/glfw_m/makefile @@ -0,0 +1,27 @@ +CC= g++ +CXXFLAGS= -c -g -O2 -std=c++11 -Wall -I../../include -D_LINUX -fPIC +TARGET= libsmelt.a + +all: objects-normal archive-normal + +dumb: CXXFLAGS += -DENABLE_DUMB +dumb: TARGET= libsmelt-dumb.a +dumb: all + +objects-normal: gfx inp sfx sys + +gfx: + $(CC) gfx_glfw.cpp $(CXXFLAGS) +sfx: + $(CC) sfx_oal.cpp $(CXXFLAGS) +inp: + $(CC) inp_glfw.cpp $(CXXFLAGS) +sys: + $(CC) sys_glfw.cpp $(CXXFLAGS) +archive-normal: + $(AR) rcs $(TARGET) gfx_glfw.o sfx_oal.o inp_glfw.o sys_glfw.o + +clean: + rm -f *.o +clean-all: clean + rm *.a diff --git a/smelt/glfw_m/sfx_dumb.cpp b/smelt/glfw_m/sfx_dumb.cpp new file mode 100644 index 0000000..4464da1 --- /dev/null +++ b/smelt/glfw_m/sfx_dumb.cpp @@ -0,0 +1,63 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * SFX dumb implementation + * This dumb implementation has everything stubbed, useful if you don't + * use the audio routines here. + * + * WARNING: This file is not intended to be used on its own! + * + */ + +SMSFX SMELT_IMPL::smSFXLoad(const char *path) +{return 0;} +SMSFX SMELT_IMPL::smSFXLoadFromMemory(const char *ptr,DWORD size) +{return 0;} +SMCHN SMELT_IMPL::smSFXPlay(SMSFX fx,int vol,int pan,float pitch,bool loop) +{return 0;} +float SMELT_IMPL::smSFXGetLengthf(SMSFX fx) +{return 0.0;} +DWORD SMELT_IMPL::smSFXGetLengthd(SMSFX fx) +{return -1;} +void SMELT_IMPL::smSFXSetLoopPoint(SMSFX fx,DWORD l,DWORD r) +{} +void SMELT_IMPL::smSFXFree(SMSFX fx) +{} +void SMELT_IMPL::smChannelVol(SMCHN chn,int vol) +{} +void SMELT_IMPL::smChannelPan(SMCHN chn,int pan) +{} +void SMELT_IMPL::smChannelPitch(SMCHN chn,float pitch) +{} +void SMELT_IMPL::smChannelPause(SMCHN chn) +{} +void SMELT_IMPL::smChannelResume(SMCHN chn) +{} +void SMELT_IMPL::smChannelStop(SMCHN chn) +{} +void SMELT_IMPL::smChannelPauseAll() +{} +void SMELT_IMPL::smChannelResumeAll() +{} +void SMELT_IMPL::smChannelStopAll() +{} +bool SMELT_IMPL::smChannelIsPlaying(SMCHN chn) +{return false;} +float SMELT_IMPL::smChannelGetPosf(SMCHN chn) +{return -1.;} +void SMELT_IMPL::smChannelSetPosf(SMCHN chn,float pos) +{} +int SMELT_IMPL::smChannelGetPosd(SMCHN chn) +{return -1;} +void SMELT_IMPL::smChannelSetPosd(SMCHN chn,int pos) +{} + +bool SMELT_IMPL::initOAL() +{ + smLog("%s:" SLINE ": I'm dumb!\n",SFX_OAL_SRCFN); + return true; +} +void SMELT_IMPL::finiOAL() +{ +} diff --git a/smelt/glfw_m/sfx_oal.cpp b/smelt/glfw_m/sfx_oal.cpp new file mode 100644 index 0000000..5b8d135 --- /dev/null +++ b/smelt/glfw_m/sfx_oal.cpp @@ -0,0 +1,368 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * GFX implementation based on OpenAL + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * + */ +#include "smelt_internal.hpp" + +static const char* SFX_OAL_SRCFN="smelt/glfw/sfx_oal.cpp"; +#ifndef ENABLE_DUMB +#ifdef ENABLE_OGG_SUPPORT +struct oggdata{const BYTE *data;DWORD size,pos;}; +static void* readVorbis(const BYTE *data,const DWORD size, ALsizei *decomp_size,ALenum *fmt,ALsizei *freq); +#endif +static void* readRiffWv(const BYTE *data,const DWORD size, ALsizei *decomp_size,ALenum *fmt,ALsizei *freq); +SMSFX SMELT_IMPL::smSFXLoad(const char *path) +{ + FILE *pFile;DWORD size,rsize; char *buff; + pFile=fopen(path,"rb"); + if(!pFile)return 0; + fseek(pFile,0,SEEK_END);size=ftell(pFile);rewind(pFile); + buff=(char*)malloc(sizeof(char)*size); + if(!buff)return 0; + rsize=fread(buff,1,size,pFile); + if(rsize!=size)return 0; + SMSFX ret=smSFXLoadFromMemory(buff,size); + free(buff); + fclose(pFile); + return ret; +} +SMSFX SMELT_IMPL::smSFXLoadFromMemory(const char *ptr,DWORD size) +{ + if(pOpenALDevice&&!mute) + { +#ifdef ENABLE_OGG_SUPPORT + bool isOgg=size>4&&ptr[0]=='O'&&ptr[1]=='g'&&ptr[2]=='g'&&ptr[3]=='S'; +#endif + void *decompdata=NULL,*decomp=NULL; + ALsizei decompsize=0,freq=0; + ALenum fmt=AL_FORMAT_STEREO16; + decompdata=readRiffWv((const BYTE*)ptr,size,&decompsize,&fmt,&freq); +#ifdef ENABLE_OGG_SUPPORT + if(!decompdata) + { + if(!isOgg)return 0; + else decompdata=readVorbis((const BYTE*)ptr,size,&decompsize,&fmt,&freq); + } +#endif + if(!decompdata)return 0; + decomp=decompdata; + ALuint buff=0;alGenBuffers(1,&buff); + alBufferData(buff,fmt,decomp,decompsize,freq); + free(decompdata);return(SMSFX)buff; + } + return 0; +} +SMCHN SMELT_IMPL::smSFXPlay(SMSFX fx,int vol,int pan,float pitch,bool loop) +{ + if(pOpenALDevice) + { + ALuint src=getSource(); + if(src) + { + if(vol<0)vol=0;if(vol>100)vol=100; + if(pan<-100)pan=-100;if(pan>100)pan=100; + alSourceStop(src); + alSourcei(src,AL_BUFFER,(ALint)fx); + alSourcef(src,AL_GAIN,((ALfloat)vol)/100.); + alSourcef(src,AL_PITCH,pitch); + alSource3f(src,AL_POSITION,((ALfloat)pan)/100.,.0,.0); + alSourcei(src,AL_LOOPING,loop?AL_TRUE:AL_FALSE); + alSourcePlay(src); + } + return src; + } + return 0; +} +float SMELT_IMPL::smSFXGetLengthf(SMSFX fx) +{ + ALuint buff=(ALuint)fx; + ALint freq; + DWORD lend=smSFXGetLengthd(fx); + alGetBufferi(buff,AL_FREQUENCY,&freq); + float ret=lend/(float)freq; + return ret; +} +DWORD SMELT_IMPL::smSFXGetLengthd(SMSFX fx) +{ + if(pOpenALDevice) + { + ALint size_b,chnc,bit; + ALuint buff=(ALuint)fx; + alGetBufferi(buff,AL_SIZE,&size_b); + alGetBufferi(buff,AL_CHANNELS,&chnc); + alGetBufferi(buff,AL_BITS,&bit); + DWORD ret=size_b*8/(chnc*bit); + return ret; + } + return -1; +} +void SMELT_IMPL::smSFXSetLoopPoint(SMSFX fx,DWORD l,DWORD r) +{ + if(pOpenALDevice) + { + ALint pt[2];pt[0]=l;pt[1]=r; + alBufferiv((ALuint)fx,AL_LOOP_POINTS_SOFT,pt); + } +} +void SMELT_IMPL::smSFXFree(SMSFX fx) +{ + if(pOpenALDevice) + { + ALuint buff=(ALuint)fx; + alDeleteBuffers(1,&buff); + } +} +void SMELT_IMPL::smChannelVol(SMCHN chn,int vol) +{ + if(pOpenALDevice) + { + if(vol<0)vol=0;if(vol>100)vol=100; + alSourcef((ALuint)chn,AL_GAIN,((ALfloat)vol)/100.); + } +} +void SMELT_IMPL::smChannelPan(SMCHN chn,int pan) +{ + if(pOpenALDevice) + { + if(pan<-100)pan=-100;if(pan>100)pan=100; + alSource3f((ALuint)chn,AL_POSITION,((ALfloat)pan)/100.,.0,.0); + } +} +void SMELT_IMPL::smChannelPitch(SMCHN chn,float pitch) +{ + if(pOpenALDevice)alSourcef((ALuint)chn,AL_PITCH,pitch); +} +void SMELT_IMPL::smChannelPause(SMCHN chn) +{ + if(pOpenALDevice)alSourcePause((ALuint)chn); +} +void SMELT_IMPL::smChannelResume(SMCHN chn) +{ + if(pOpenALDevice)alSourcePlay((ALuint)chn); +} +void SMELT_IMPL::smChannelStop(SMCHN chn) +{ + if(pOpenALDevice)alSourceStop((ALuint)chn); +} +void SMELT_IMPL::smChannelPauseAll() +{ + if(pOpenALDevice) + { + ALCcontext *ctx=alcGetCurrentContext(); + alcSuspendContext(ctx); + } +} +void SMELT_IMPL::smChannelResumeAll() +{ + if(pOpenALDevice) + { + ALCcontext *ctx=alcGetCurrentContext(); + alcProcessContext(ctx); + } +} +void SMELT_IMPL::smChannelStopAll() +{ + if(pOpenALDevice) + { + for(int i=0;i<scnt;++i)alSourceStop(src[i]); + } +} +bool SMELT_IMPL::smChannelIsPlaying(SMCHN chn) +{ + if(pOpenALDevice) + { + ALint state=AL_STOPPED; + alGetSourceiv((ALuint)chn,AL_SOURCE_STATE,&state); + return state==AL_PLAYING; + } + return false; +} +float SMELT_IMPL::smChannelGetPosf(SMCHN chn) +{ + if(pOpenALDevice) + { + ALfloat ret; + alGetSourcef((ALuint)chn,AL_SEC_OFFSET,&ret); + return (float)ret; + } + return -1.; +} +void SMELT_IMPL::smChannelSetPosf(SMCHN chn,float pos) +{ + if(pOpenALDevice)alSourcef((ALuint)chn,AL_SEC_OFFSET,(ALfloat)pos); +} +int SMELT_IMPL::smChannelGetPosd(SMCHN chn) +{ + if(pOpenALDevice) + { + ALint ret; + alGetSourcei((ALuint)chn,AL_SAMPLE_OFFSET,&ret); + return (int)ret; + } + return -1; +} +void SMELT_IMPL::smChannelSetPosd(SMCHN chn,int pos) +{ + if(pOpenALDevice)alSourcei((ALuint)chn,AL_SAMPLE_OFFSET,(ALint)pos); +} + +#ifdef ENABLE_OGG_SUPPORT +static size_t oggRead(void *ptr,size_t size,size_t nmemb,void *ds) +{ + oggdata *data=(oggdata*)ds; + const DWORD avail=data->size-data->pos; + size_t want=nmemb*size; + if(want>avail)want=avail-(avail%size); + if(want>0) + { + memcpy(ptr,data->data+data->pos,want); + data->pos+=want; + } + return want/size; +} +static int oggSeek(void *ds,ogg_int64_t offset,int whence) +{ + oggdata *data=(oggdata*)ds; + ogg_int64_t pos=0; + switch(whence) + { + case SEEK_SET:pos=offset;break; + case SEEK_CUR:pos=((ogg_int64_t)data->pos)+offset;break; + case SEEK_END:pos=((ogg_int64_t)data->size)+offset;break; + default: return -1; + } + if((pos<0)||(pos>((ogg_int64_t)data->size)))return -1; + data->pos=(DWORD)pos; + return 0; +} +static long oggLocate(void *ds) +{ + oggdata* data=(oggdata*)ds; + return (long)data->pos; +} +static int oggClose(void *ds){return 0;} + +static ov_callbacks oggrt={oggRead,oggSeek,oggClose,oggLocate}; +static void* readVorbis(const BYTE *data,const DWORD size, ALsizei *decomp_size,ALenum *fmt,ALsizei *freq) +{ + oggdata adata={data,size,0}; + OggVorbis_File vf; + memset(&vf,0,sizeof(vf)); + if(ov_open_callbacks(&adata,&vf,NULL,0,oggrt)==0) + { + int bs=0; + vorbis_info *info=ov_info(&vf,-1); + *decomp_size=0; + *fmt=(info->channels==1)?AL_FORMAT_MONO16:AL_FORMAT_STEREO16; + *freq=info->rate; + if(!(info->channels==1||info->channels==2)){ov_clear(&vf);return NULL;} + char buf[1024*16];long rc=0;size_t allocated=1024*16; + BYTE *ret=(ALubyte*)malloc(allocated); + while((rc=ov_read(&vf,buf,sizeof(buf),0,2,1,&bs))!=0) + { + if(rc>0) + { + *decomp_size+=rc; + if((unsigned)*decomp_size>=allocated) + { + allocated<<=1; + ALubyte *tmp=(ALubyte*)realloc(ret,allocated); + if(!tmp){free(ret);ret=NULL;break;} + ret=tmp; + } + memcpy(ret+(*decomp_size-rc),buf,rc); + } + } + ov_clear(&vf); + return ret; + } + return NULL; +} +#endif +static void* readRiffWv(const BYTE *data,const DWORD size, ALsizei *decomp_size,ALenum *fmt,ALsizei *freq) +{ + if(data[0x0]!='R'||data[0x1]!='I'||data[0x2]!='F'||data[0x3]!='F')return NULL; + if(data[0x8]!='W'||data[0x9]!='A'||data[0xA]!='V'||data[0xB]!='E')return NULL; + if(data[0xC]!='f'||data[0xD]!='m'||data[0xE]!='t'||data[0xF]!=' ')return NULL; + if(data[0x16]==2) + { + if(data[0x22]==16)*fmt=AL_FORMAT_STEREO16; + else if(data[0x22]==8)*fmt=AL_FORMAT_STEREO8; + else return NULL; + } + else if(data[0x16]==1) + { + if(data[0x22]==16)*fmt=AL_FORMAT_MONO16; + else if(data[0x22]==8)*fmt=AL_FORMAT_MONO8; + else return NULL; + }else return NULL; + *decomp_size=(ALsizei)(data[0x28]|(data[0x29]<<8L)|(data[0x2A]<<16L)|(data[0x2B]<<24L)); + *freq=(ALsizei)(data[0x18]|(data[0x19]<<8L)|(data[0x1A]<<16L)|(data[0x1B]<<24L)); + ALubyte *ret=(ALubyte*)malloc(*decomp_size); + memcpy(ret,data+44,*decomp_size); + return ret; +} +ALuint SMELT_IMPL::getSource() +{ + for(int i=0;i<scnt;++i) + { + ALint state=AL_PLAYING; + alGetSourceiv(src[i],AL_SOURCE_STATE,&state); + if(!(state==AL_PLAYING||state==AL_PAUSED))return src[i]; + } + if(scnt>=SRC_MAX)return 0; + ALuint ret=0; + alGenSources(1,&ret);if(!ret)return 0; + src[scnt++]=ret;return ret; +} +bool SMELT_IMPL::initOAL() +{ + if(pOpenALDevice)return true; + scnt=0;memset(src,0,sizeof(src)); + smLog("%s:" SLINE ": Initializing OpenAL...\n",SFX_OAL_SRCFN); + ALCdevice *dev=alcOpenDevice(NULL); + if(!dev) + { + smLog("%s:" SLINE ": alcOpenDevice() failed.\n",SFX_OAL_SRCFN); + return mute=true; + } + ALint caps[]={ALC_FREQUENCY,44100,0}; + ALCcontext *ctx=alcCreateContext(dev,caps); + if(!ctx) + { + smLog("%s:" SLINE ": alcCreateContext() failed.\n",SFX_OAL_SRCFN); + return mute=true; + } + alcMakeContextCurrent(ctx);alcProcessContext(ctx); + smLog("%s:" SLINE ": Done OpenAL initialization\n",SFX_OAL_SRCFN); + smLog("%s:" SLINE ": AL_VENDOR: %s\n",SFX_OAL_SRCFN,(char*)alGetString(AL_VENDOR)); + smLog("%s:" SLINE ": AL_RENDERER: %s\n",SFX_OAL_SRCFN,(char*)alGetString(AL_RENDERER)); + smLog("%s:" SLINE ": AL_VERSION: %s\n",SFX_OAL_SRCFN,(char*)alGetString(AL_VERSION)); + const char* ext=(const char*)alGetString(AL_EXTENSIONS); + lpp=strstr(ext,"AL_SOFT_loop_points")!=NULL; + if(!lpp)smLog("%s:" SLINE ": Warning: loop points not supported. Please recompile with OpenAL Soft.\n",SFX_OAL_SRCFN); + pOpenALDevice=(void*)dev; + return true; +} +void SMELT_IMPL::finiOAL() +{ + if(pOpenALDevice) + { + for(int i=0;i<scnt;++i)alSourceStop(src[i]); + alDeleteSources(scnt,src);scnt=0;memset(src,0,sizeof(src)); + ALCcontext *ctx=alcGetCurrentContext(); + ALCdevice *dev=alcGetContextsDevice(ctx); + alcMakeContextCurrent(NULL); + alcSuspendContext(ctx);alcDestroyContext(ctx); + alcCloseDevice(dev);pOpenALDevice=NULL; + } +} +#else +#include "sfx_dumb.cpp" +#endif //ifndef ENABLE_DUMB diff --git a/smelt/glfw_m/smelt_config.hpp b/smelt/glfw_m/smelt_config.hpp new file mode 100644 index 0000000..d215d36 --- /dev/null +++ b/smelt/glfw_m/smelt_config.hpp @@ -0,0 +1,30 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * Configuration header for SDL version + * + * Modify this header according to your own requirements. + * + */ + +/* + * Maximum audio channels. + * (How many audio can be played simultaneously?) + */ +#define SRC_MAX 128 + +/* + * Vertex buffer size. + */ +#define VERTEX_BUFFER_SIZE 4000 + +/* + * Uncomment this to build a "dumb" version with no audio routines. + */ +//#define ENABLE_DUMB + +/* + * Undefine this to disable ogg support. + */ +#define ENABLE_OGG_SUPPORT diff --git a/smelt/glfw_m/smelt_internal.hpp b/smelt/glfw_m/smelt_internal.hpp new file mode 100644 index 0000000..2619b12 --- /dev/null +++ b/smelt/glfw_m/smelt_internal.hpp @@ -0,0 +1,249 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * Internal header for GLFW version + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * + */ +#ifndef SMELT_INTERNAL_H +#define SMELT_INTERNAL_H + +#include "../../include/smelt.hpp" +#include "smelt_config.hpp" +#include <cstdio> +#include <cstring> +#include <cstdlib> +#include <ctime> +#include <cstdarg> +#include <dirent.h> +#include <unistd.h> +#define GLEW_STATIC +#include <GL/glew.h> +#include <GLFW/glfw3.h> +#ifndef ENABLE_DUMB +#include <AL/al.h> +#include <AL/alc.h> +#include <AL/alext.h> +#ifdef ENABLE_OGG_SUPPORT +#include <ogg/ogg.h> +#include <vorbis/vorbisfile.h> +#endif +#endif +#ifdef WIN32 +#include <windows.h> +#include <intrin.h> +#endif + +#define xstr(s) str(s) +#define str(s) #s +#define SLINE xstr(__LINE__) + +class TOpenGLDevice +{ +public: + bool have_base_opengl; +}; + +struct glTexture; +class TRenderTargetList +{ +public: + int w,h,ms; + SMTEX tex; + GLuint depth,frame,colorms,sframe,sdepth,scolor; + TRenderTargetList *next; +}; +class TTextureList +{ +public: + SMTEX tex; + int w,h; + TTextureList *next; +}; +class TInputEventList +{ +public: + smInpEvent e; + TInputEventList *next; +}; + +class SMELT_IMPL:public SMELT +{ +public: + virtual void smRelease(); + virtual bool smInit(); + virtual void smFinale(); + virtual void smMainLoop(); + virtual void smUpdateFunc(smHook func); + virtual void smUpdateFunc(smHandler* h); + virtual void smUnFocFunc(smHook func); + virtual void smUnFocFunc(smHandler* h); + virtual void smFocFunc(smHook func); + virtual void smFocFunc(smHandler* h); + virtual void smQuitFunc(smHook func); + virtual void smQuitFunc(smHandler* h); + virtual void smWinTitle(const char* title); + virtual bool smIsActive(); + virtual void smNoSuspend(bool para); + virtual void smVidMode(int resX,int resY,bool _windowed); + virtual void smLogFile(const char* path); + virtual void smLog(const char* format,...); + virtual void smScreenShot(const char* path); + + virtual void smSetFPS(int fps); + virtual float smGetFPS(); + virtual float smGetDelta(); + virtual float smGetTime(); + + virtual SMSFX smSFXLoad(const char *path); + virtual SMSFX smSFXLoadFromMemory(const char *ptr,DWORD size); + virtual SMCHN smSFXPlay(SMSFX fx,int vol=100,int pan=0,float pitch=1.,bool loop=0); + virtual float smSFXGetLengthf(SMSFX fx); + virtual DWORD smSFXGetLengthd(SMSFX fx); + virtual void smSFXSetLoopPoint(SMSFX fx,DWORD l,DWORD r); + virtual void smSFXFree(SMSFX fx); + + virtual void smChannelVol(SMCHN chn,int vol); + virtual void smChannelPan(SMCHN chn,int pan); + virtual void smChannelPitch(SMCHN chn,float pitch); + virtual void smChannelPause(SMCHN chn); + virtual void smChannelResume(SMCHN chn); + virtual void smChannelStop(SMCHN chn); + virtual void smChannelPauseAll(); + virtual void smChannelResumeAll(); + virtual void smChannelStopAll(); + virtual bool smChannelIsPlaying(SMCHN chn); + virtual float smChannelGetPosf(SMCHN chn); + virtual void smChannelSetPosf(SMCHN chn,float pos); + virtual int smChannelGetPosd(SMCHN chn); + virtual void smChannelSetPosd(SMCHN chn,int pos); + + virtual void smGetMouse2f(float *x,float *y); + virtual void smSetMouse2f(float x,float y); + virtual void smSetMouseGrab(bool enabled); + virtual int smGetWheel(); + virtual bool smIsMouseOver(); + virtual int smGetKeyState(int key); + virtual int smGetKey(); + virtual bool smGetInpEvent(smInpEvent *e); + + virtual bool smRenderBegin2D(bool ztest=0,SMTRG trg=0); + virtual bool smRenderBegin3D(float fov,bool ztest=0,SMTRG trg=0); + virtual bool smRenderEnd(); + virtual void sm3DCamera6f2v(float *pos,float *rot); + virtual void sm2DCamera5f3v(float *pos,float *dpos,float *rot); + virtual void smMultViewMatrix(float *mat); + virtual void smClrscr(DWORD color,bool clearcol=true,bool cleardep=true); + virtual void smRenderLinefd(float x1,float y1,float z1,float x2,float y2,float z2,DWORD color); + virtual void smRenderLinefvd(float *p1,float *p2,DWORD color); + virtual void smRenderTriangle(smTriangle *t); + virtual void smRenderQuad(smQuad *q); + virtual smVertex* smGetVertArray(); + virtual void smDrawVertArray(int prim,SMTEX texture,int blend,int _primcnt); + virtual void smDrawCustomIndexedVertices(smVertex* vb,WORD* ib,int vbc,int ibc,int blend,SMTEX texture); + + virtual SMTRG smTargetCreate(int w,int h,int ms=0); + virtual SMTEX smTargetTexture(SMTRG targ); + virtual void smTargetFree(SMTRG targ); + + virtual SMTEX smTextureCreate(int w,int h); + virtual SMTEX smTextureLoad(const char *path); + virtual SMTEX smTextureLoadFromMemory(const char *ptr,DWORD size); + virtual void smTextureFree(SMTEX tex); + virtual void smTextureOpt(int potopt=TPOT_NONPOT,int filter=TFLT_LINEAR); + virtual int smTextureGetWidth(SMTEX tex,bool original=false); + virtual int smTextureGetHeight(SMTEX tex,bool original=false); + virtual DWORD* smTextureLock(SMTEX tex,int l,int t,int w,int h,bool ro=true); + virtual void smTexutreUnlock(SMTEX tex); +//internal routines&variables... + static SMELT_IMPL* getInterface(); + void focusChange(bool actif); + + void *hwnd; + bool Active; + char curError[256]; + + bool (*pUpdateFunc)(); + bool (*pUnFocFunc)(); + bool (*pFocFunc)(); + bool (*pQuitFunc)(); + smHandler *updateHandler,*unFocHandler,*focHandler,*quitHandler; + const char *Icon; + char winTitle[256]; + int scrw,scrh; + int dispw,disph; + bool windowed,vsync; + char logFile[256]; + int limfps; + bool hideMouse,noSuspend; + + TOpenGLDevice *pOpenGLDevice; + smVertex *vertexArray; + smVertex *vertexBuf; + GLushort *indexBuf; + GLuint IndexBufferObject; + GLuint VertexBufferObject; + GLuint VertexArrayObject; + GLuint ShaderProgram; + GLuint fragshader,vertshader; + int loc_tex,loc_mmodv,loc_mproj; + float mmodv[16],mproj[16]; + TRenderTargetList *targets; + TRenderTargetList *curTarget; + TTextureList *textures; + bool tdmode; + int primcnt,primType,primBlend,filtermode; + SMTEX primTex,emptyTex; + bool zbufenabled; + bool checkGLExtension(const char *extlist,const char *ext); + void unloadGLEntryPoints(); + bool loadGLEntryPoints(); + bool initOGL(); + void finiOGL(); + bool restOGL(); + bool confOGL(); + void batchOGL(bool endScene=false); + void configTexture(glTexture *t,int w,int h,DWORD *px,bool compress=true); + void bindTexture(glTexture *t); + bool buildTarget(TRenderTargetList *pTarget,GLuint texid,int w,int h,int ms); + SMTEX buildTexture(int w,int h,DWORD *px); + void setBlend(int blend); + void configProjectionMatrix2D(int w,int h); + void configProjectionMatrix3D(int w,int h,float fov); + DWORD* decodeImage(BYTE *data,const char *fn,DWORD size,int &w,int &h); + + void *pOpenALDevice; + bool mute,lpp; + bool initOAL(); + void finiOAL(); +#ifndef ENABLE_DUMB + int scnt; + ALuint src[SRC_MAX]; + ALuint getSource(); +#endif + + int posz,lkey; + float posx,posy; + int keymods; + bool mouseOver,captured; + char keyz[256]; + bool keylst[256]; + TInputEventList *inpQueue; + void initInput(); + void clearQueue(); + void buildEvent(int type,int k,int scan,int flags,int x,int y); + bool procGLFWEvent(); + int GLFWKeyToSMKey(int glfwkey); + + float timeDelta,updateFPSDelay,fps,timeS; + DWORD fixDelta,t0; + int fcnt; + DWORD dt; +private: + SMELT_IMPL(); +}; +extern SMELT_IMPL *pSM; +#endif diff --git a/smelt/glfw_m/smmath_priv.hpp b/smelt/glfw_m/smmath_priv.hpp new file mode 100644 index 0000000..90f0e2a --- /dev/null +++ b/smelt/glfw_m/smmath_priv.hpp @@ -0,0 +1,165 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * Math header & implementation for the core + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * + */ +#ifndef SMMATH_H +#define SMMATH_H +#include <cmath> +#include <cstddef> +#define sqr(x) ((x)*(x)) +#define EPS 1e-6 +#ifndef PI +#define PI 3.14159265358979323846f +#endif + +class smMath +{ +public: + static double deg2rad(double deg){return deg/180.*PI;} + static double rad2deg(double rad){return rad/PI*180.;} + static double clamprad(double a){while(a<0)a+=2*PI;while(a>2*PI)a-=2*PI;return a;} + static double clampdeg(double a){while(a<0)a+=360.;while(a>360)a-=360.;return a;} +}; +class smvec2d +{ +public: + float x,y; + smvec2d(float _x,float _y){x=_x;y=_y;} + smvec2d(){x=y=.0;} + float l(){return sqrtf(sqr(x)+sqr(y));} + void normalize(){float L=l();if(L<EPS)return;x/=L;y/=L;} + smvec2d getNormalized(){float L=l();if(L<EPS)return smvec2d(0,0);return smvec2d(x/L,y/L);} + void swap(){float t=x;x=y;y=t;} + void rotate(float rad){float tx=x*cosf(rad)+y*sinf(rad),ty=y*cosf(rad)-x*sinf(rad);x=tx,y=ty;} + smvec2d getRotate(float rad){float tx=x*cosf(rad)+y*sinf(rad),ty=y*cosf(rad)-x*sinf(rad);return smvec2d(tx,ty);} + friend smvec2d operator -(smvec2d a,smvec2d b){return smvec2d(a.x-b.x,a.y-b.y);} + friend smvec2d operator +(smvec2d a,smvec2d b){return smvec2d(a.x+b.x,a.y+b.y);} + friend float operator |(smvec2d a,smvec2d b){return a.x*b.x+a.y*b.y;} + friend float operator *(smvec2d a,smvec2d b){return a.x*b.y-b.x*a.y;} + friend smvec2d operator *(float a,smvec2d b){return smvec2d(a*b.x,a*b.y);} + friend smvec2d operator *(smvec2d a,float b){return smvec2d(b*a.x,b*a.y);} + friend float operator ^(smvec2d a,smvec2d b){return (a|b)/a.l()/b.l();} +}; + +class smvec3d +{ +public: + float x,y,z; + smvec3d(float _x,float _y,float _z){x=_x;y=_y;z=_z;} + smvec3d(smvec2d a,float _z=.0){x=a.x;y=a.y;z=_z;} + smvec3d(){x=y=z=.0;} + float l(){return sqrtf(sqr(x)+sqr(y)+sqr(z));} + void normalize(){float L=l();if(L<EPS)return;x/=L;y/=L;z/=L;} + smvec3d getNormalized(){float L=l();if(L<EPS)return smvec3d(0,0,0);return smvec3d(x/L,y/L,z/L);} + friend smvec3d operator -(smvec3d a,smvec3d b){return smvec3d(a.x-b.x,a.y-b.y,a.z-b.z);} + friend smvec3d operator +(smvec3d a,smvec3d b){return smvec3d(a.x+b.x,a.y+b.y,a.z+b.z);} + friend float operator |(smvec3d a,smvec3d b){return a.x*b.x+a.y*b.y+a.z*b.z;} + friend smvec3d operator *(smvec3d a,smvec3d b){return smvec3d(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);} + friend smvec3d operator *(float a,smvec3d b){return smvec3d(a*b.x,a*b.y,a*b.z);} + friend smvec3d operator *(smvec3d a,float b){return smvec3d(b*a.x,b*a.y,b*a.z);} + friend float operator ^(smvec3d a,smvec3d b){return (a|b)/a.l()/b.l();} +}; + +class smvec4d +{ +public: + float x,y,z,w; + smvec4d(float _x,float _y,float _z,float _w){x=_x;y=_y;z=_z;w=_w;} + smvec4d(smvec3d a,float _w=.0){x=a.x;y=a.y;z=a.z;w=_w;} + smvec4d(){x=y=z=w=.0;} + float l(){return sqrt(sqr(x)+sqr(y)+sqr(z)+sqr(w));} + void normalize(){float L=l();if(L<EPS)return;x/=L;y/=L;z/=L;w/=L;} + smvec4d getNormalized(){float L=l();if(L<EPS)return smvec4d(0,0,0,0);return smvec4d(x/L,y/L,z/L,w/L);} + friend smvec4d operator -(smvec4d a,smvec4d b){return smvec4d(a.x-b.x,a.y-b.y,a.z-b.z,a.w-b.w);} + friend smvec4d operator +(smvec4d a,smvec4d b){return smvec4d(a.x+b.x,a.y+b.y,a.z+b.z,a.w+b.w);} + friend float operator |(smvec4d a,smvec4d b){return a.x*b.x+a.y*b.y+a.z*b.z+a.w*b.w;} + //Note: this doesn't do a real 4D cross product. + friend smvec4d operator *(smvec4d a,smvec4d b){return smvec4d(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x,1);} + friend smvec4d operator *(float a,smvec4d b){return smvec4d(a*b.x,a*b.y,a*b.z,a*b.w);} + friend smvec4d operator *(smvec4d a,float b){return smvec4d(b*a.x,b*a.y,b*a.z,b*a.w);} + friend float operator ^(smvec4d a,smvec4d b){return (a|b)/a.l()/b.l();} +}; + +class smMatrix +{ +public: + float m[16]; + /* sf 0 1 2 3 + * 0 00 04 08 12 + * 1 01 05 09 13 + * 2 02 06 10 14 + * 3 03 07 11 15 + */ + smMatrix(){for(int i=0;i<16;++i)m[i]=.0;} + smMatrix(const float* _m){memcpy(m,_m,sizeof(m));} + smMatrix(const smMatrix ©){for(int i=0;i<16;++i)m[i]=copy.m[i];} + float* operator [](int s){if(s>=0&&s<4)return m+s*4;else return NULL;} + void clear(){for(int i=0;i<16;++i)m[i]=.0;} + void loadIdentity(){clear();m[0]=m[5]=m[10]=m[15]=1.;} + void translate(float x,float y,float z) + { + smMatrix tmp;tmp.loadIdentity(); + tmp.m[12]=x;tmp.m[13]=y;tmp.m[14]=z; + *this=*this*tmp; + } + void rotate(float a,float x,float y,float z) + { + if(smvec3d(x,y,z).l()<=EPS)return; + if(fabsf(smvec3d(x,y,z).l()-1)>EPS) + { + smvec3d a(x,y,z);a.normalize(); + x=a.x;y=a.y;z=a.z; + } + smMatrix tmp; + float c=cosf(a),s=sinf(a); + tmp.m[ 0]=x*x*(1-c)+c; + tmp.m[ 4]=x*y*(1-c)-z*s; + tmp.m[ 8]=x*z*(1-c)+y*s; + tmp.m[ 1]=y*x*(1-c)+z*s; + tmp.m[ 5]=y*y*(1-c)+c; + tmp.m[ 9]=y*z*(1-c)-x*s; + tmp.m[ 2]=x*z*(1-c)-y*s; + tmp.m[ 6]=y*z*(1-c)+x*s; + tmp.m[10]=z*z*(1-c)+c; + tmp.m[15]=1; + *this=*this*tmp; + } + void lookat(smvec3d eye,smvec3d at,smvec3d up) + { + smvec3d f=at-eye;f.normalize();up.normalize(); + smvec3d s=f*up;smvec3d u=s.getNormalized()*f; + m[0]= s.x;m[4]= s.y;m[ 8]= s.z;m[12]=0; + m[1]= u.x;m[5]= u.y;m[ 9]= u.z;m[13]=0; + m[2]=-f.x;m[6]=-f.y;m[10]=-f.z;m[14]=0; + m[3]= 0;m[7]= 0;m[11]= 0;m[15]=1; + } + friend smMatrix operator *(smMatrix a,smMatrix b) + { + smMatrix ret; + for(int i=0;i<4;++i) + for(int j=0;j<4;++j) + for(int k=0;k<4;++k) + ret[j][i]+=a[k][i]*b[j][k]; + return ret; + } + friend smvec3d operator *(smMatrix a,smvec3d b) + { + return smvec3d(a[0][0]*b.x+a[1][0]*b.y+a[2][0]*b.z, + a[0][1]*b.x+a[1][1]*b.y+a[2][1]*b.z, + a[0][2]*b.x+a[1][2]*b.y+a[2][2]*b.z); + } + friend smvec4d operator *(smMatrix a,smvec4d b) + { + return smvec4d(a[0][0]*b.x+a[1][0]*b.y+a[2][0]*b.z+a[3][0]*b.w, + a[0][1]*b.x+a[1][1]*b.y+a[2][1]*b.z+a[3][1]*b.w, + a[0][2]*b.x+a[1][2]*b.y+a[2][2]*b.z+a[3][2]*b.w, + a[0][3]*b.x+a[1][3]*b.y+a[2][3]*b.z+a[3][3]*b.w); + } +}; +#endif diff --git a/smelt/glfw_m/sys_glfw.cpp b/smelt/glfw_m/sys_glfw.cpp new file mode 100644 index 0000000..a5829f3 --- /dev/null +++ b/smelt/glfw_m/sys_glfw.cpp @@ -0,0 +1,334 @@ +// -*- 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" +#include <thread> +#include <chrono> +static const char* SYS_GLFW_SRCFN="smelt/glfw_m/sys_glfw.cpp"; +int refcnt=0; +SMELT_IMPL *pSM=0; +char lasterr[1024]; + +void glfwErrorHandler(int err,const char* desc); +void glfwFocChangeHandler(GLFWwindow*,int foc); +void glfwCursorEnterHandler(GLFWwindow*,int ent); +void glfwKBEventHandler(GLFWwindow* window,int key,int scancode,int action,int mods); +void glfwMouseButtonHandler(GLFWwindow* w,int btn,int action,int mods); +void glfwMouseMotionHandler(GLFWwindow*,double x,double y); +void glfwMouseWheelHandler(GLFWwindow* w,double x,double y); + +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_GLFW_SRCFN); + smLog("%s:" SLINE ": SMELT api version %d\n",SYS_GLFW_SRCFN,SMELT_APILEVEL); + time_t t=time(NULL); + smLog("%s:" SLINE ": Date %s",SYS_GLFW_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_GLFW_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=(char*)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_GLFW_SRCFN,cpuName); + free(loced); + + GlobalMemoryStatus(&mem_st); + smLog("%s:" SLINE ": Memory: %ldK total, %ldK free\n", SYS_GLFW_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_GLFW_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_GLFW_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_GLFW_SRCFN,totalm,freem); + fclose(a); +#endif + glfwSetErrorCallback(glfwErrorHandler); + if(!glfwInit()) + { + smLog("%s:" SLINE ": glfwInit() failed with error %s\n",SYS_GLFW_SRCFN,lasterr); + return false; + } + GLFWmonitor *moninfo=glfwGetPrimaryMonitor(); + dispw=glfwGetVideoMode(moninfo)->width; + disph=glfwGetVideoMode(moninfo)->height; + smLog("%s:" SLINE ": Screen: %d x %d\n",SYS_GLFW_SRCFN,dispw,disph); + glfwWindowHint(GLFW_RED_BITS,8); + glfwWindowHint(GLFW_GREEN_BITS,8); + glfwWindowHint(GLFW_BLUE_BITS,8); + glfwWindowHint(GLFW_ALPHA_BITS,8); + glfwWindowHint(GLFW_DEPTH_BITS,16); + glfwWindowHint(GLFW_DOUBLEBUFFER,1); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3); + glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE); + GLFWwindow *screen=glfwCreateWindow(windowed?scrw:dispw,windowed?scrh:disph,winTitle,NULL,NULL); + hwnd=(void*)screen; + if(!hwnd) + { + smLog("%s:" SLINE ": glfwCreateWindow() failed with error %s\n",SYS_GLFW_SRCFN,lasterr); + glfwTerminate(); + return false; + } + glfwMakeContextCurrent(screen); + glfwSwapInterval(vsync?1:0); + if(!windowed) + { + mouseOver=true; + if(!pSM->Active)pSM->focusChange(true); + } + if(hideMouse)glfwSetInputMode(screen,GLFW_CURSOR,GLFW_CURSOR_HIDDEN); + glfwSetWindowFocusCallback(screen,glfwFocChangeHandler); + glfwSetCursorEnterCallback(screen,glfwCursorEnterHandler); + glfwSetKeyCallback(screen,glfwKBEventHandler); + glfwSetCursorPosCallback(screen,glfwMouseMotionHandler); + glfwSetMouseButtonCallback(screen,glfwMouseButtonHandler); + glfwSetScrollCallback(screen,glfwMouseWheelHandler); + initInput(); + if(!initOGL()){smFinale();return false;} + if(!initOAL()){smFinale();return false;} + t0=DWORD(glfwGetTime()*1000.);dt=fcnt=0;fps=.0; + updateFPSDelay=.0; + return true; +} + +void SMELT_IMPL::smFinale() +{ + smLog("%s:" SLINE ": Cleaning up...\n",SYS_GLFW_SRCFN); + clearQueue();finiOAL();finiOGL(); + glfwDestroyWindow((GLFWwindow*)hwnd);glfwTerminate();hwnd=0; +} + +void SMELT_IMPL::smMainLoop() +{ + if(!hwnd)return smLog("%s:" SLINE ": Error: SMELT is not initialized.\n",SYS_GLFW_SRCFN); + if(!pUpdateFunc&&!updateHandler) return smLog("%s:" SLINE ": UpdateFunc is not defined.\n",SYS_GLFW_SRCFN); + Active=true; + for(;;) + { + glfwPollEvents(); + bool loopcont=true; + loopcont=procGLFWEvent(); + if(!loopcont)break; + if(Active||noSuspend) + { + DWORD ticks; + do{ticks=DWORD(glfwGetTime()*1000.);dt=ticks-t0;}while(dt<1); + if(dt>=fixDelta) + { + timeDelta=dt/1000.; + if(timeDelta>0.2)timeDelta=fixDelta?fixDelta/1000.:.01; + ++fcnt;updateFPSDelay+=timeDelta;t0=ticks;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+3<fixDelta)std::this_thread::sleep_for(std::chrono::milliseconds(1)); + }else std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + clearQueue();Active=false; +} +void SMELT_IMPL::smUpdateFunc(smHook func){pUpdateFunc=func;} +void SMELT_IMPL::smUpdateFunc(smHandler* h){updateHandler=h;} +void SMELT_IMPL::smUnFocFunc(smHook func){pUnFocFunc=func;} +void SMELT_IMPL::smUnFocFunc(smHandler* h){unFocHandler=h;} +void SMELT_IMPL::smFocFunc(smHook func){pFocFunc=func;} +void SMELT_IMPL::smFocFunc(smHandler* h){focHandler=h;} +void SMELT_IMPL::smQuitFunc(smHook func){pQuitFunc=func;} +void SMELT_IMPL::smQuitFunc(smHandler* h){quitHandler=h;} +void SMELT_IMPL::smWinTitle(const char *title){strcpy(winTitle,title);} +bool SMELT_IMPL::smIsActive(){return Active;} +void SMELT_IMPL::smNoSuspend(bool para){noSuspend=para;} +void SMELT_IMPL::smVidMode(int resX,int resY,bool _windowed) +{ + if(vertexArray)return; + if(!pOpenGLDevice)scrw=resX,scrh=resY,windowed=_windowed; + else if(windowed!=_windowed) + { + windowed=_windowed; + glfwSetWindowSize((GLFWwindow*)hwnd,windowed?scrw:dispw,windowed?scrh:disph); + restOGL(); + if(!windowed){mouseOver=true;if(!pSM->Active)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) + { + //glFinish(); + //glReadPixels(0,0,screen->w,screen->h,GL_RGB,GL_UNSIGNED_BYTE,surface->pixels); + } +} +void SMELT_IMPL::smSetFPS(int fps) +{ + vsync=(fps==FPS_VSYNC); + if(pOpenGLDevice)glfwSwapInterval(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=0;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::procGLFWEvent() +{ + if(glfwWindowShouldClose((GLFWwindow*)hwnd)) + { + bool accepted=true; + if(pSM->pQuitFunc&&pSM->pQuitFunc())accepted=false; + if(pSM->quitHandler&&quitHandler->handlerFunc())accepted=false; + if(accepted)return false; + } + return true; +} +void glfwErrorHandler(int err,const char* desc) +{ + strcpy(lasterr,desc); +} +void glfwFocChangeHandler(GLFWwindow*,int foc) +{ + pSM->focusChange(foc); +} +void glfwCursorEnterHandler(GLFWwindow*,int ent) +{ + pSM->mouseOver=ent; +} +void glfwKBEventHandler(GLFWwindow* window,int key,int scancode,int action,int mods) +{ + if(action==GLFW_RELEASE) + { + pSM->keymods=mods; + pSM->buildEvent(INPUT_KEYUP,key,0,0,-1,-1); + } + else + { + pSM->keymods=mods; + if((pSM->keymods&GLFW_MOD_ALT)&&((key==GLFW_KEY_ENTER)||(key==GLFW_KEY_KP_ENTER))) + pSM->smVidMode(pSM->scrw,pSM->scrh,!pSM->windowed); + pSM->buildEvent(INPUT_KEYDOWN,key,0,0,-1,-1); + } +} +void glfwMouseButtonHandler(GLFWwindow* w,int btn,int action,int mods) +{ + double x,y;glfwGetCursorPos(w,&x,&y); + if(action==GLFW_PRESS) + { + if(btn==GLFW_MOUSE_BUTTON_LEFT) + pSM->buildEvent(INPUT_MBUTTONDOWN,SMK_LBUTTON,0,0,x,y); + if(btn==GLFW_MOUSE_BUTTON_RIGHT) + pSM->buildEvent(INPUT_MBUTTONDOWN,SMK_RBUTTON,0,0,x,y); + if(btn==GLFW_MOUSE_BUTTON_MIDDLE) + pSM->buildEvent(INPUT_MBUTTONDOWN,SMK_MBUTTON,0,0,x,y); + } + else + { + if(btn==GLFW_MOUSE_BUTTON_LEFT) + pSM->buildEvent(INPUT_MBUTTONUP,SMK_LBUTTON,0,0,x,y); + if(btn==GLFW_MOUSE_BUTTON_RIGHT) + pSM->buildEvent(INPUT_MBUTTONUP,SMK_RBUTTON,0,0,x,y); + if(btn==GLFW_MOUSE_BUTTON_MIDDLE) + pSM->buildEvent(INPUT_MBUTTONUP,SMK_MBUTTON,0,0,x,y); + } +} +void glfwMouseMotionHandler(GLFWwindow*,double x,double y) +{ + pSM->buildEvent(INPUT_MOUSEMOVE,0,0,0,x,y); +} +void glfwMouseWheelHandler(GLFWwindow* w,double x,double y) +{ + double cx,cy;glfwGetCursorPos(w,&cx,&cy); + if(y>0)pSM->buildEvent(INPUT_MOUSEWHEEL,1,0,0,cx,cy); + if(y<0)pSM->buildEvent(INPUT_MOUSEWHEEL,-1,0,0,cx,cy); +} |