diff options
Diffstat (limited to 'extensions')
-rw-r--r-- | extensions/smanim.cpp | 196 | ||||
-rw-r--r-- | extensions/smbmfont.cpp | 219 | ||||
-rw-r--r-- | extensions/smdatapack.cpp | 177 | ||||
-rw-r--r-- | extensions/smentity.cpp | 207 | ||||
-rw-r--r-- | extensions/smgrid.cpp | 111 | ||||
-rw-r--r-- | extensions/smttfont.cpp | 144 |
6 files changed, 1054 insertions, 0 deletions
diff --git a/extensions/smanim.cpp b/extensions/smanim.cpp new file mode 100644 index 0000000..d57292b --- /dev/null +++ b/extensions/smanim.cpp @@ -0,0 +1,196 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * Animation implementation + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * This library is developed for the BLR series games. + */ +#include "smanim.hpp" +#include <cstdio> +#include <cstring> +#define METAWARN(s) printf("metafile warning at line %d: %s\n",lc,s) +SMELT* smAnmFile::sm=NULL; +void smAnmFile::parseMeta(const char* meta,DWORD size) +{ + const char* cp=meta; + bool inAnim=false; + int lc=0; + smAnmInfo cur; + while(cp-meta<=size) + { + int cc=0; + for(;*(cp+cc)!='\n'&&(cp+cc-meta<=size);++cc); + char line[65]; + strncpy(line,cp,cc+1);line[cc]='\0'; + cp+=cc+1;++lc; + if(inAnim&&line[0]!='F'&&line[0]!='E'){METAWARN("Only instruction F is allowed between A and E.");continue;} + if(line[0]=='E') + { + if(!inAnim)METAWARN("No animation to end..."); + else{inAnim=false;am[std::string(cur.name)]=cur;} + } + if(line[0]=='A') + { + if(inAnim)METAWARN("Already in an animation definition..."); + else + { + inAnim=true; + int cn=0;while(line[cn+2]!=',')++cn; + cur.name=new char[cn];strncpy(cur.name,line+2,cn); + cur.name[cn-1]='\0';cur.mode=0;cur.fc=0; + if(!strcmp(line+3+cn,"loop"))cur.mode=1; + if(!strcmp(line+3+cn,"bidi"))cur.mode=2; + } + } + if(line[0]=='F') + { + if(!inAnim)METAWARN("Cannot define frames outside animation..."); + else + { + int cn=0;while(line[cn+2]!=',')++cn; + cur.frames[cur.fc].path=new char[cn]; + cur.frames[cur.fc].name=NULL; + strncpy(cur.frames[cur.fc].path,line+2,cn); + cur.frames[cur.fc].path[cn-1]='\0'; + sscanf(line+3+cn,"%f,%f,%f,%f,%d",&cur.frames[cur.fc].rect.x, + &cur.frames[cur.fc].rect.y,&cur.frames[cur.fc].rect.w,&cur.frames[cur.fc].rect.h, + &cur.framedur[cur.fc]); + if(xm.find(std::string(cur.frames[cur.fc].path))!=xm.end()) + cur.frames[cur.fc].tex=xm[std::string(cur.frames[cur.fc].path)]; + else + { + char *texct=anm.getFilePtr(cur.frames[cur.fc].path); + DWORD texsz=anm.getFileSize(cur.frames[cur.fc].path); + cur.frames[cur.fc].tex=xm[std::string(cur.frames[cur.fc].path)] + =sm->smTextureLoadFromMemory(texct,texsz); + anm.releaseFilePtr(cur.frames[cur.fc].path); + } + ++cur.fc; + } + } + if(line[0]=='S') + { + smTexInfo t; + int cn=0;while(line[cn+2]!=',')++cn; + t.name=new char[cn+1];strncpy(t.name,line+2,cn+1); + t.name[cn]='\0'; + int cn2=0;while(line[cn+3+cn2]!=',')++cn2; + t.path=new char[cn2+1];strncpy(t.path,line+3+cn,cn2+1); + t.path[cn2]='\0'; + sscanf(line+4+cn+cn2,"%f,%f,%f,%f",&t.rect.x,&t.rect.y,&t.rect.w,&t.rect.h); + if(xm.find(std::string(t.path))!=xm.end()) + t.tex=xm[std::string(t.path)]; + else + { + char *texct=anm.getFilePtr(t.path); + DWORD texsz=anm.getFileSize(t.path); + t.tex=xm[std::string(t.path)] + =sm->smTextureLoadFromMemory(texct,texsz); + anm.releaseFilePtr(t.path); + } + tm[std::string(t.name)]=t; + } + if(line[0]=='I') + { + char* mptr=anm.getFilePtr(line+2); + DWORD msez=anm.getFileSize(line+2); + parseMeta(mptr,msez); + anm.releaseFilePtr(line+2); + } + } +} +bool smAnmFile::loadAnmFromMemory(const char* ptr,DWORD size) +{ + sm=smGetInterface(SMELT_APILEVEL); + anm.openDtpFromMemory(ptr,size); + xm.clear();tm.clear();am.clear(); + char* mptr=anm.getFilePtr("content.meta"); + DWORD msez=anm.getFileSize("content.meta"); + parseMeta(mptr,msez); + anm.releaseFilePtr("content.meta"); +} +void smAnmFile::close() +{ + anm.closeDtp(); + for(std::map<std::string,smTexInfo>::iterator i=tm.begin();i!=tm.end();++i) + {delete i->second.name;delete i->second.path;} + tm.clear(); + for(std::map<std::string,smAnmInfo>::iterator i=am.begin();i!=am.end();++i) + { + delete i->second.name; + for(int j=0;j<i->second.fc;++j) + delete i->second.frames[j].path; + } + am.clear(); + for(std::map<std::string,SMTEX>::iterator i=xm.begin();i!=xm.end();++i) + sm->smTextureFree(i->second); + xm.clear(); + sm->smRelease(); +} +smTexInfo* smAnmFile::getTextureInfo(const char* name) +{return &tm.at(name);} +smAnmInfo* smAnmFile::getAnimationInfo(const char* name) +{return &am.at(name);} + +smAnimation2D::smAnimation2D(smAnmInfo a):smEntity2D(a.frames[0].tex,a.frames[0].rect) +{ + ai=a;cf=mf=r=0; + for(int i=0;i<ai.fc;++i)mf+=ai.framedur[i]; +} +void smAnimation2D::updateAnim(int f) +{ + if(ai.mode==0){cf+=f;if(cf>mf)cf=mf;} + if(ai.mode==1){cf+=f;if(cf>mf)cf-=mf;} + if(ai.mode==2) + { + if(r){cf-=f;if(cf<0)r=0,cf=-cf;} + else{cf+=f;if(cf>mf)r=1,cf=2*mf-cf;} + } + int l=0,r=ai.framedur[0],ff=0; + for(int i=0;i<ai.fc;++i) + { + if(cf>l&&cf<=r){ff=i;break;} + l+=ai.framedur[i];r+=ai.framedur[i+1]; + } + setTexture(ai.frames[ff].tex); + setTextureRectv(ai.frames[ff].rect); +} +void smAnimation2D::resetAnim() +{ + cf=mf=r=0; + setTexture(ai.frames[0].tex); + setTextureRectv(ai.frames[0].rect); +} + +smAnimation3D::smAnimation3D(smAnmInfo a):smEntity3D(a.frames[0].tex,a.frames[0].rect) +{ + ai=a;cf=mf=r=0; + for(int i=0;i<ai.fc;++i)mf+=ai.framedur[i]; +} +void smAnimation3D::updateAnim(int f) +{ + if(ai.mode==0){cf+=f;if(cf>mf)cf=mf;} + if(ai.mode==1){cf+=f;if(cf>mf)cf-=mf;} + if(ai.mode==2) + { + if(r){cf-=f;if(cf<0)r=0,cf=-cf;} + else{cf+=f;if(cf>mf)r=1,cf=2*mf-cf;} + } + int l=0,r=ai.framedur[0],ff=0; + for(int i=0;i<ai.fc;++i) + { + if(cf>l&&cf<=r){ff=i;break;} + l+=ai.framedur[i];r+=ai.framedur[i+1]; + } + setTexture(ai.frames[ff].tex); + setTextureRectv(ai.frames[ff].rect); +} +void smAnimation3D::resetAnim() +{ + cf=mf=r=0; + setTexture(ai.frames[0].tex); + setTextureRectv(ai.frames[0].rect); +} diff --git a/extensions/smbmfont.cpp b/extensions/smbmfont.cpp new file mode 100644 index 0000000..22f9280 --- /dev/null +++ b/extensions/smbmfont.cpp @@ -0,0 +1,219 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * Bitmap font support implementation + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * This library is developed for the BLR series games. + */ +#include "smbmfont.hpp" +#include <cstdio> +#include <cstring> +#include <cstdarg> + +SMELT *smBMFont::sm=NULL; +SMELT *smBMFontw::sm=NULL; + +void smBMFont::parseMeta(const char* meta,DWORD size) +{ + const char* cp=meta; + char line[65]; + int cc,cod,pa,pb;smTexRect rct; + while(cp-meta<=size) + { + cc=0; + for(;*(cp+cc)!='\n'&&cp+cc-meta<=size;++cc); + strncpy(line,cp,cc);if(line[cc]=='\n')line[cc]='\0'; + cp+=cc+1; + char* tp=strchr(line,','); + if(tp)*tp='\0';else continue; + sscanf(tp+1,"%d,%f,%f,%f,%f,%d,%d",&cod,&rct.x,&rct.y,&rct.w,&rct.h,&pb,&pa); + if(cod>=0&&cod<256) + { + if(xm.find(std::string(line))==xm.end()) + { + char* texct=anm.getFilePtr(line); + DWORD texsz=anm.getFileSize(line); + xm[std::string(line)]=sm->smTextureLoadFromMemory(texct,texsz); + anm.releaseFilePtr(line); + } + chars[cod]=new smEntity2D(xm[std::string(line)],rct); + pdb[cod]=pb;pda[cod]=pa;if(hadv<rct.h)hadv=(float)rct.h; + } + } +} +bool smBMFont::loadAnmFromMemory(const char* ptr,DWORD size) +{ + sm=smGetInterface(SMELT_APILEVEL); + anm.openDtpFromMemory(ptr,size);hadv=0; + xm.clear();memset(chars,0,sizeof(chars)); + char* mptr=anm.getFilePtr("content.meta"); + DWORD msez=anm.getFileSize("content.meta"); + parseMeta(mptr,msez); + anm.releaseFilePtr("content.meta"); + setBlend(BLEND_ALPHABLEND); + setColor(0xFFFFFFFF); +} +void smBMFont::close() +{ + anm.closeDtp(); + for(int i=0;i<256;++i)if(chars[i]){delete chars[i];chars[i]=NULL;} + for(std::map<std::string,SMTEX>::iterator i=xm.begin();i!=xm.end();++i) + sm->smTextureFree(i->second); + xm.clear(); + sm->smRelease(); +} +void smBMFont::render(float x,float y,float z,int align,float *rw,const char* text) +{ + float width=0,cw=0,ofs=x; + const char* t=text; + while(*t) + { + cw=0; + for(;*t&&*t!='\n';++t) + { + if(chars[(int)*t]) + cw+=chars[(int)*t]->_w()+pdb[(int)*t]+pda[(int)*t]; + } + if(cw>width)width=cw; + while(*t=='\n')++t; + } + width*=sc; + if(rw)*rw=width; + if(align==ALIGN_CENTER)ofs-=width/2.; + if(align==ALIGN_RIGHT)ofs-=width; + while(*text) + { + if(*text=='\n') + { + y+=hadv*sc;ofs=x; + if(align==ALIGN_CENTER)ofs-=width/2.; + if(align==ALIGN_RIGHT)ofs-=width; + } + else + { + if(chars[(int)*text]) + { + ofs+=pdb[(int)*text]*sc; + chars[(int)*text]->setZ(z); + chars[(int)*text]->setColor(color); + chars[(int)*text]->setBlend(b); + chars[(int)*text]->render(ofs,y,0,sc); + ofs+=(chars[(int)*text]->_w()+pda[(int)*text])*sc; + } + } + ++text; + } +} +void smBMFont::printf(float x,float y,float z,int align,float *rw,const char* format,...) +{ + char buf[1024]; + va_list vl; + va_start(vl,format); + vsnprintf(buf,sizeof(buf)-1,format,vl); + va_end(vl); + buf[sizeof(buf)-1]='\0'; + render(x,y,z,align,rw,buf); +} + +void smBMFontw::parseMeta(char* meta,DWORD size) +{ + char* cp=meta; + char line[65]; + int cc,cod,pa,pb;smTexRect rct; + while(cp-meta<=size) + { + cc=0; + for(;*(cp+cc)!='\n'&&cp+cc-meta<=size;++cc); + strncpy(line,cp,cc);if(line[cc]=='\n')line[cc]='\0'; + cp+=cc+1; + char* tp=strchr(line,','); + if(tp)*tp='\0';else continue; + sscanf(tp+1,"%d,%f,%f,%f,%f,%d,%d",&cod,&rct.x,&rct.y,&rct.w,&rct.h,&pb,&pa); + if(cod>=WCHAR_MIN&&cod<=WCHAR_MAX) + { + if(xm.find(std::string(line))==xm.end()) + { + char* texct=anm.getFilePtr(line); + DWORD texsz=anm.getFileSize(line); + xm[std::string(line)]=sm->smTextureLoadFromMemory(texct,texsz); + anm.releaseFilePtr(line); + } + chars[cod]=new smEntity2D(xm.find(std::string(line))->second,rct); + pdb[cod]=pb;pda[cod]=pa;if(hadv<rct.h)hadv=(float)rct.h; + } + } +} +bool smBMFontw::loadAnmFromMemory(char* ptr,DWORD size) +{ + sm=smGetInterface(SMELT_APILEVEL); + anm.openDtpFromMemory(ptr,size);hadv=0; + xm.clear();chars.clear();pdb.clear();pda.clear(); + char* mptr=anm.getFilePtr("content.meta"); + DWORD msez=anm.getFileSize("content.meta"); + parseMeta(mptr,msez); + anm.releaseFilePtr("content.meta"); +} +void smBMFontw::close() +{ + anm.closeDtp(); + for(std::map<wchar_t,smEntity2D*>::iterator i=chars.begin();i!=chars.end();++i)if(i->second){delete i->second;i->second=NULL;} + for(std::map<std::string,SMTEX>::iterator i=xm.begin();i!=xm.end();++i) + sm->smTextureFree(i->second); + xm.clear();chars.clear();pdb.clear();pda.clear(); + sm->smRelease(); +} +void smBMFontw::render(float x,float y,float z,int align,float *rw,const wchar_t* text) +{ + float width=0,cw=0,ofs=x; + const wchar_t* t=text; + while(*t) + { + cw=0; + for(;*t&&*t!='\n';++t) + { + if(chars[*t]) + cw+=chars[*t]->_w()+pdb[*t]+pda[*t]; + } + if(cw>width)width=cw; + while(*t=='\n')++t; + } + width*=sc; + if(rw)*rw=width; + if(align==ALIGN_CENTER)ofs-=width/2.; + if(align==ALIGN_RIGHT)ofs-=width; + while(*text) + { + if(*text=='\n') + { + y+=hadv*sc;ofs=x; + if(align==ALIGN_CENTER)ofs-=width/2.; + if(align==ALIGN_RIGHT)ofs-=width; + } + else + { + if(chars[*text]) + { + ofs+=pdb[*text]*sc; + chars[*text]->setZ(z); + chars[*text]->setColor(color); + chars[*text]->setBlend(b); + chars[*text]->render(ofs,y,0,sc); + ofs+=(chars[*text]->_w()+pda[*text])*sc; + } + } + ++text; + } +} +void smBMFontw::printf(float x,float y,float z,int align,float *rw,const wchar_t* format,...) +{ + wchar_t buf[1024]; + va_list vl; + va_start(vl,format); + vswprintf(buf,sizeof(buf)-1,format,vl); + va_end(vl); + buf[sizeof(buf)-1]='\0'; + render(x,y,z,align,rw,buf); +} diff --git a/extensions/smdatapack.cpp b/extensions/smdatapack.cpp new file mode 100644 index 0000000..2e77324 --- /dev/null +++ b/extensions/smdatapack.cpp @@ -0,0 +1,177 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * DaTaPack format support implementation + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * This library is developed for the BLR series games. + */ +#include "smdatapack.hpp" +#include <cstdio> +#include <cstring> +#define gzgetDWORD(f) ((gzgetc(f)<<24)|(gzgetc(f)<<16)|(gzgetc(f)<<8)|(gzgetc(f)))&0xFFFFFFFF +#define gch ((*(cp++))&0xFF) +#define mmgetDWORD ((gch<<24)|(gch<<16)|(gch<<8)|(gch))&0xFFFFFFFF +#define gzputDWORD(f,a) gzputc(f,a>>24);gzputc(f,(a>>16)&0xFF);gzputc(f,(a>>8)&0xFF);gzputc(f,a&0xFF); +bool smDtpFileR::openDtp(const char* path) +{ + file=gzopen(path,"r"); + if(!file)return false;enmemory=false;msize=0; + if(gzgetc(file)!='D')return false; + if(gzgetc(file)!='T')return false; + if(gzgetc(file)!='P')return false; + fcnt=gzgetc(file); + for(int i=0;i<fcnt;++i) + { + int pl=gzgetc(file); + smFileInfo f; + f.path=new char[pl+1];f.data=NULL; + for(int j=0;j<pl;++j)f.path[j]=gzgetc(file); + f.path[pl]='\0'; + f.size=gzgetDWORD(file); + f.offset=gzgetDWORD(file); + f.crc=gzgetDWORD(file); + m[std::string(f.path)]=f; + } +} +bool smDtpFileR::openDtpFromMemory(const char* ptr,DWORD size) +{ + enmemory=true;msize=size; + if(!ptr||size<4)return false; + if(ptr[0]!='D'||ptr[1]!='T'||ptr[2]!='P')return false; + cp=ptr+3;bp=ptr; + fcnt=*(cp++); + for(int i=0;i<fcnt;++i) + { + int pl=*(cp++); + smFileInfo f; + f.path=new char[pl+1];f.data=NULL; + for(int j=0;j<pl;++j)f.path[j]=*(cp++); + f.path[pl]='\0'; + f.size=mmgetDWORD; + f.offset=mmgetDWORD; + f.crc=mmgetDWORD; + m[std::string(f.path)]=f; + } +} +void smDtpFileR::closeDtp() +{ + for(std::map<std::string,smFileInfo>::iterator i=m.begin();i!=m.end();++i) + { + delete[] i->second.path;i->second.path=NULL; + if(i->second.data){delete[] i->second.data;i->second.data=NULL;} + i->second.size=i->second.offset=i->second.crc=0; + } + fcnt=0; + m.clear();if(!enmemory){gzclose(file);file=0;} +} +char* smDtpFileR::getFirstFile(){return m.begin()->second.path;} +char* smDtpFileR::getLastFile(){return (--m.end())->second.path;} +char* smDtpFileR::getNextFile(const char* path) +{ + std::map<std::string,smFileInfo>::iterator i=m.find(std::string(path)); + if(i==m.end()||(++i)==m.end())return NULL; + return i->second.path; +} +char* smDtpFileR::getPrevFile(const char* path) +{ + std::map<std::string,smFileInfo>::iterator i=m.find(std::string(path)); + if(i==m.end()||i==m.begin())return NULL;--i; + return i->second.path; +} +char* smDtpFileR::getFilePtr(const char* path) +{ + std::string fns(path); + if(m.find(fns)==m.end()){printf("error: file not found in the archive.\n");return NULL;} + if(m.at(fns).data)return m.at(fns).data; + else + { + if(!m.at(fns).size){printf("error: empty file.\n");return NULL;} + if(!enmemory) + gzseek(file,m[fns].offset,SEEK_SET); + else + cp=bp+m[fns].offset; + m[fns].data=new char[m[fns].size]; + if(!enmemory) + { + int r=gzread(file,m[fns].data,m[fns].size); + if(r<m[fns].size){delete[] m[fns].data;printf("error: file size mismatch.\n");return m[fns].data=NULL;} + } + else + { + if((cp-bp)+m[fns].size>msize){delete[] m[fns].data;printf("error: file size mismatch.\n");return m[fns].data=NULL;} + memcpy(m[fns].data,cp,m[fns].size); + } + DWORD crc=crc32(0,(Bytef*)m[fns].data,m[fns].size); + if(crc!=m[fns].crc) + {delete[] m[fns].data;printf("error: crc mismatch.\n");return m[fns].data=NULL;} + return m[fns].data; + } +} +void smDtpFileR::releaseFilePtr(const char* path) +{ + std::string fns(path); + if(m.find(fns)==m.end()){printf("error: file not found in the archive.\n");return;} + if(m[fns].data) + { + delete[] m[fns].data; + m[fns].data=NULL; + } +} +DWORD smDtpFileR::getFileSize(const char* path) +{if(m.find(std::string(path))==m.end()){printf("error: file not found in the archive.\n");return 0;}return m[std::string(path)].size;} + +smDtpFileW::smDtpFileW(){fcnt=0;} +bool smDtpFileW::addFile(const char* path,const char* realpath) +{ + FILE *pFile;DWORD size,rsize; + pFile=fopen(realpath,"rb"); + if(!pFile)return false; + fseek(pFile,0,SEEK_END);size=ftell(pFile);rewind(pFile); + if(!size)return false;files[fcnt].data=NULL; + files[fcnt].data=new char[size]; + if(!files[fcnt].data)return false; + files[fcnt].path=new char[strlen(path)+1]; + strcpy(files[fcnt].path,path); + rsize=fread(files[fcnt].data,1,size,pFile); + if(rsize!=size) + { + delete[] files[fcnt].data;files[fcnt].data=NULL; + delete[] files[fcnt].path;files[fcnt].path=NULL; + return false; + } + files[fcnt].size=size; + files[fcnt].crc=crc32(0,(Bytef*)files[fcnt].data,files[fcnt].size); + ++fcnt; + fclose(pFile); + return true; +} +bool smDtpFileW::writeDtp(const char* path) +{ + gzFile file=gzopen(path,"w"); + gzputs(file,"DTP");gzputc(file,fcnt); + int metasize=4; + for(int i=0;i<fcnt;++i)metasize+=strlen(files[i].path)+1+4+4+4; + files[0].offset=metasize; + for(int i=1;i<fcnt;++i)files[i].offset=files[i-1].offset+files[i-1].size; + for(int i=0;i<fcnt;++i) + { + gzputc(file,strlen(files[i].path)); + gzputs(file,files[i].path); + gzputDWORD(file,files[i].size); + gzputDWORD(file,files[i].offset); + gzputDWORD(file,files[i].crc); + } + for(int i=0;i<fcnt;++i)gzwrite(file,(voidpc)files[i].data,files[i].size); + gzclose(file); + for(int i=0;i<fcnt;++i) + { + files[i].size=files[i].offset=files[i].crc=0; + delete[] files[i].data;files[i].data=NULL; + delete[] files[i].path;files[i].path=NULL; + } + fcnt=0; + return true; +} diff --git a/extensions/smentity.cpp b/extensions/smentity.cpp new file mode 100644 index 0000000..00660e5 --- /dev/null +++ b/extensions/smentity.cpp @@ -0,0 +1,207 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * Entity implementation + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * + */ +#include "smentity.hpp" +#include "smmath.hpp" +#include <cstring> +#include <cstdio> +SMELT *smEntity2D::sm=NULL; +SMELT *smEntity3D::sm=NULL; + +smEntity2D::smEntity2D(SMTEX tex,float _x,float _y,float _w,float _h) +{ + sm=smGetInterface(SMELT_APILEVEL); + tx=_x;ty=_y;w=_w;h=_h; + if(tex) + { + texw=sm->smTextureGetWidth(tex); + texh=sm->smTextureGetHeight(tex); + }else texw=texh=1.; + ctrx=ctry=0;quad.tex=tex; + quad.v[0].tx=_x/texw;quad.v[0].ty=_y/texh; + quad.v[1].tx=(_x+_w)/texw;quad.v[1].ty=_y/texh; + quad.v[2].tx=(_x+_w)/texw;quad.v[2].ty=(_y+_h)/texh; + quad.v[3].tx=_x/texw;quad.v[3].ty=(_y+_h)/texh; + for(int i=0;i<4;++i){quad.v[i].z=.5f;quad.v[i].col=0xFFFFFFFF;} + quad.blend=BLEND_ALPHABLEND; +} +smEntity2D::smEntity2D(SMTEX tex,smTexRect rect) +{ + sm=smGetInterface(SMELT_APILEVEL); + tx=rect.x;ty=rect.y;w=rect.w;h=rect.h; + if(tex) + { + texw=sm->smTextureGetWidth(tex); + texh=sm->smTextureGetHeight(tex); + }else texw=texh=1.; + ctrx=ctry=0;quad.tex=tex; + quad.v[0].tx=rect.x/texw;quad.v[0].ty=rect.y/texh; + quad.v[1].tx=(rect.x+rect.w)/texw;quad.v[1].ty=rect.y/texh; + quad.v[2].tx=(rect.x+rect.w)/texw;quad.v[2].ty=(rect.y+rect.h)/texh; + quad.v[3].tx=rect.x/texw;quad.v[3].ty=(rect.y+rect.h)/texh; + for(int i=0;i<4;++i){quad.v[i].z=.5f;quad.v[i].col=0xFFFFFFFF;} + quad.blend=BLEND_ALPHABLEND; +} +smEntity2D::smEntity2D(const smEntity2D ©) +{ + memcpy(this,©,sizeof(smEntity2D)); + sm=smGetInterface(SMELT_APILEVEL); +} +void smEntity2D::render(float x,float y,float rot,float wsc,float hsc) +{ + if(hsc<EPS)hsc=wsc; + float cx0=-ctrx*wsc,cy0=-ctry*hsc; + float cx1=(w-ctrx)*wsc,cy1=(h-ctry)*hsc; + float c=cosf(rot),s=sinf(rot); + quad.v[0].x=cx0*c-cy0*s+x;quad.v[0].y=cx0*s+cy0*c+y; + quad.v[1].x=cx1*c-cy0*s+x;quad.v[1].y=cx1*s+cy0*c+y; + quad.v[2].x=cx1*c-cy1*s+x;quad.v[2].y=cx1*s+cy1*c+y; + quad.v[3].x=cx0*c-cy1*s+x;quad.v[3].y=cx0*s+cy1*c+y; + sm->smRenderQuad(&quad); +} +void smEntity2D::setTexture(SMTEX tex) +{ + float ntw,nth; + if(tex) + { + ntw=sm->smTextureGetWidth(tex); + nth=sm->smTextureGetHeight(tex); + }else ntw=nth=1.; + quad.tex=tex; + if(ntw!=texw||nth!=texh) + { + float tx1=quad.v[0].tx*texw,ty1=quad.v[0].ty*texh; + float tx2=quad.v[2].tx*texw,ty2=quad.v[2].ty*texh; + texw=ntw;texh=nth; + tx1/=texw;ty1/=texh;tx2/=texw;ty2/=texh; + quad.v[0].tx=tx1;quad.v[0].ty=ty1; + quad.v[1].tx=tx2;quad.v[1].ty=ty1; + quad.v[2].tx=tx2;quad.v[2].ty=ty2; + quad.v[3].tx=tx1;quad.v[3].ty=ty2; + } +} +void smEntity2D::setTextureRect4f(float _x,float _y,float _w,float _h) +{ + tx=_x;ty=_y;w=_w;h=_h; + quad.v[0].tx=_x/texw;quad.v[0].ty=_y/texh; + quad.v[1].tx=(_x+_w)/texw;quad.v[1].ty=_y/texh; + quad.v[2].tx=(_x+_w)/texw;quad.v[2].ty=(_y+_h)/texh; + quad.v[3].tx=_x/texw;quad.v[3].ty=(_y+_h)/texh; +} +void smEntity2D::setTextureRectv(smTexRect rect){setTextureRect4f(rect.x,rect.y,rect.w,rect.h);} +void smEntity2D::setColor(DWORD col,int v) +{ + if(v>=0&&v<4)quad.v[v].col=col; + else for(int i=0;i<4;++i)quad.v[i].col=col; +} +void smEntity2D::setZ(float z,int v) +{ + if(v>=0&&v<4)quad.v[v].z=z; + else for(int i=0;i<4;++i)quad.v[i].z=z; +} +void smEntity2D::setBlend(int blend){quad.blend=blend;} +void smEntity2D::setCentre(float x,float y){ctrx=x;ctry=y;} + +smEntity3D::smEntity3D(SMTEX tex,float _x,float _y,float _w,float _h) +{ + sm=smGetInterface(SMELT_APILEVEL); + tx=_x;ty=_y;w=_w;h=_h; + if(tex) + { + texw=sm->smTextureGetWidth(tex); + texh=sm->smTextureGetHeight(tex); + }else texw=texh=1.; + ctrx=ctry=0;quad.tex=tex; + quad.v[0].tx=_x/texw;quad.v[0].ty=_y/texh; + quad.v[1].tx=(_x+_w)/texw;quad.v[1].ty=_y/texh; + quad.v[2].tx=(_x+_w)/texw;quad.v[2].ty=(_y+_h)/texh; + quad.v[3].tx=_x/texw;quad.v[3].ty=(_y+_h)/texh; + for(int i=0;i<4;++i){quad.v[i].z=.5f;quad.v[i].col=0xFFFFFFFF;} + quad.blend=BLEND_ALPHABLEND; +} +smEntity3D::smEntity3D(SMTEX tex,smTexRect rect) +{ + sm=smGetInterface(SMELT_APILEVEL); + tx=rect.x;ty=rect.y;w=rect.w;h=rect.h; + if(tex) + { + texw=sm->smTextureGetWidth(tex); + texh=sm->smTextureGetHeight(tex); + }else texw=texh=1.; + ctrx=ctry=0;quad.tex=tex; + quad.v[0].tx=rect.x/texw;quad.v[0].ty=rect.y/texh; + quad.v[1].tx=(rect.x+rect.w)/texw;quad.v[1].ty=rect.y/texh; + quad.v[2].tx=(rect.x+rect.w)/texw;quad.v[2].ty=(rect.y+rect.h)/texh; + quad.v[3].tx=rect.x/texw;quad.v[3].ty=(rect.y+rect.h)/texh; + for(int i=0;i<4;++i){quad.v[i].z=.5f;quad.v[i].col=0xFFFFFFFF;} + quad.blend=BLEND_ALPHABLEND; +} +smEntity3D::smEntity3D(const smEntity3D ©) +{ + memcpy(this,©,sizeof(smEntity3D)); + sm=smGetInterface(SMELT_APILEVEL); +} +void smEntity3D::render9f(float x,float y,float z,float ra,float rx,float ry,float rz,float wsc,float hsc) +{ + if(hsc<EPS)hsc=wsc; + float cx0=-ctrx*wsc,cy0=-ctry*hsc; + float cx1=(w-ctrx)*wsc,cy1=(h-ctry)*hsc; + smvec3d a,r;smMatrix m; + a=smvec3d(cx0,cy0,0);m.loadIdentity();m.rotate(ra,rx,ry,rz);r=m*a; + quad.v[0].x=r.x;quad.v[0].y=r.y;quad.v[0].z=r.z; + a=smvec3d(cx1,cy0,0);m.loadIdentity();m.rotate(ra,rx,ry,rz);r=m*a; + quad.v[1].x=r.x;quad.v[1].y=r.y;quad.v[1].z=r.z; + a=smvec3d(cx1,cy1,0);m.loadIdentity();m.rotate(ra,rx,ry,rz);r=m*a; + quad.v[2].x=r.x;quad.v[2].y=r.y;quad.v[2].z=r.z; + a=smvec3d(cx0,cy1,0);m.loadIdentity();m.rotate(ra,rx,ry,rz);r=m*a; + quad.v[3].x=r.x;quad.v[3].y=r.y;quad.v[3].z=r.z; + sm->smRenderQuad(&quad); +} +void smEntity3D::renderfv(float* pos,float* rot,float* scale) +{ + render9f(pos[0],pos[1],pos[2],rot[0],rot[1],rot[2],rot[3],scale[0],scale[1]); +} +void smEntity3D::setTexture(SMTEX tex) +{ + float ntw,nth; + if(tex) + { + ntw=sm->smTextureGetWidth(tex); + nth=sm->smTextureGetHeight(tex); + }else ntw=nth=1.; + quad.tex=tex; + if(ntw!=texw||nth!=texh) + { + float tx1=quad.v[0].tx*texw,ty1=quad.v[0].ty*texh; + float tx2=quad.v[2].tx*texw,ty2=quad.v[2].ty*texh; + texw=ntw;texh=nth; + tx1/=texw;ty1/=texh;tx2/=texw;ty2/=texh; + quad.v[0].tx=tx1;quad.v[0].ty=ty1; + quad.v[1].tx=tx2;quad.v[1].ty=ty1; + quad.v[2].tx=tx2;quad.v[2].ty=ty2; + quad.v[3].tx=tx1;quad.v[3].ty=ty2; + } +} +void smEntity3D::setTextureRect4f(float _x,float _y,float _w,float _h) +{ + tx=_x;ty=_y;w=_w;h=_h; + quad.v[0].tx=_x/texw;quad.v[0].ty=_y/texh; + quad.v[1].tx=(_x+_w)/texw;quad.v[1].ty=_y/texh; + quad.v[2].tx=(_x+_w)/texw;quad.v[2].ty=(_y+_h)/texh; + quad.v[3].tx=_x/texw;quad.v[3].ty=(_y+_h)/texh; +} +void smEntity3D::setTextureRectv(smTexRect rect){setTextureRect4f(rect.x,rect.y,rect.w,rect.h);} +void smEntity3D::setColor(DWORD col,int v) +{ + if(v>=0&&v<4)quad.v[v].col=col; + else for(int i=0;i<4;++i)quad.v[i].col=col; +} +void smEntity3D::setBlend(int blend){quad.blend=blend;} +void smEntity3D::setCentre(float x,float y){ctrx=x;ctry=y;} diff --git a/extensions/smgrid.cpp b/extensions/smgrid.cpp new file mode 100644 index 0000000..d78864f --- /dev/null +++ b/extensions/smgrid.cpp @@ -0,0 +1,111 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * Distortion grid implementation + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * + */ +#include "smgrid.hpp" +#include <cstring> +SMELT *smGrid::sm=0; +smGrid::smGrid(int _cc,int _rc) +{ + sm=smGetInterface(SMELT_APILEVEL); + cc=_cc;rc=_rc;cw=ch=.0; + quad.tex=0;quad.blend=BLEND_ALPHABLEND; + pos=new smVertex[cc*rc]; + for(int i=0;i<cc*rc;++i) + { + pos[i].x=pos[i].y=pos[i].z=.0; + pos[i].tx=pos[i].ty=.0; + pos[i].col=0xFFFFFFFF; + } +} +smGrid::smGrid(const smGrid ©) +{ + sm=smGetInterface(SMELT_APILEVEL); + cc=copy.cc;rc=copy.rc;cw=copy.cw;ch=copy.ch; + quad=copy.quad;tx=copy.tx;ty=copy.ty;w=copy.w;h=copy.h; + pos=new smVertex[cc*rc];memcpy(pos,copy.pos,sizeof(smVertex)*cc*rc); +} +smGrid::~smGrid(){delete[] pos;sm->smRelease();} +smGrid& smGrid::operator =(const smGrid ©) +{ + if(this!=©) + { + sm=smGetInterface(SMELT_APILEVEL); + cc=copy.cc;rc=copy.rc;cw=copy.cw;ch=copy.ch; + quad=copy.quad;tx=copy.tx;ty=copy.ty;w=copy.w;h=copy.h; + delete[] pos;pos=new smVertex[cc*rc]; + memcpy(pos,copy.pos,sizeof(smVertex)*cc*rc); + } + return *this; +} +void smGrid::setTexture(SMTEX tex){quad.tex=tex;} +void smGrid::setTextureRect4f(float _x,float _y,float _w,float _h) +{ + float tw,th; + tx=_x;ty=_y;w=_w;h=_h; + if(quad.tex) + { + tw=(float)sm->smTextureGetWidth(quad.tex); + th=(float)sm->smTextureGetHeight(quad.tex); + } + else tw=w,th=h; + cw=w/(cc-1);ch=h/(rc-1); + for(int i=0;i<rc;++i) + for(int j=0;j<cc;++j) + { + pos[i*cc+j].tx=(tx+j*cw)/tw; + pos[i*cc+j].ty=(ty+i*ch)/th; + pos[i*cc+j].x=j*cw; + pos[i*cc+j].y=i*ch; + } +} +void smGrid::setTextureRectv(smTexRect rect){setTextureRect4f(rect.x,rect.y,rect.w,rect.h);} +void smGrid::setBlend(int blend){quad.blend=blend;} +void smGrid::setColor(int c,int r,DWORD col){if(c<cc&&r<rc)pos[r*cc+c].col=col;} +void smGrid::setPos(int c,int r,float x,float y,float z,int ref) +{ + if(c<cc&&r<rc) + { + if(ref==GRID_REFCENTER)x+=cw*(cc-1)/2,y+=ch*(rc-1)/2; + if(ref==GRID_REFNODE)x+=c*cw,y+=r*ch; + if(ref==GRID_REFCURRENT)x+=pos[r*cc+c].x,y+=pos[r*cc+c].y; + pos[r*cc+c].x=x; + pos[r*cc+c].y=y; + } +} +void smGrid::clear(DWORD col) +{ + for(int i=0;i<rc;++i) + for(int j=0;j<cc;++j) + { + pos[i*cc+j].x=j*cw; + pos[i*cc+j].y=i*ch; + pos[i*cc+j].z=.0; + pos[i*cc+j].col=col; + } +} +void smGrid::render(float x,float y) +{ + for(int i=0;i<rc-1;++i) + for(int j=0;j<cc-1;++j) + { + int id=i*cc+j; + for(int k=0;k<4;++k) + { + int sub=k<2?id+k:id+cc+3-k; + quad.v[k].tx=pos[sub].tx; + quad.v[k].ty=pos[sub].ty; + quad.v[k].x=x+pos[sub].x; + quad.v[k].y=y+pos[sub].y; + quad.v[k].z=pos[sub].z; + quad.v[k].col=pos[sub].col; + } + sm->smRenderQuad(&quad); + } +} diff --git a/extensions/smttfont.cpp b/extensions/smttfont.cpp new file mode 100644 index 0000000..f3e8b1c --- /dev/null +++ b/extensions/smttfont.cpp @@ -0,0 +1,144 @@ +// -*- C++ -*- +/* + * Simple MultimEdia LiTerator(SMELT) + * by Chris Xiong 2015 + * Truetype font support implementation + * + * WARNING: This library is in development and interfaces would be very + * unstable. + * This library is developed for the BLR series games. + */ +#include "smttfont.hpp" + +SMELT *smTTChar::sm=NULL; + +void smTTChar::free(){if(quad.tex){sm->smTextureFree(quad.tex);quad.tex=0;sm->smRelease();}} +bool smTTChar::setChar(wchar_t c,FT_Face ttface) +{ + if(!sm)sm=smGetInterface(SMELT_APILEVEL); + FT_GlyphSlot slot=ttface->glyph; + FT_UInt glyph_index=FT_Get_Char_Index(ttface,c); + if(FT_Load_Glyph(ttface,glyph_index,FT_LOAD_DEFAULT))return false; + if(FT_Render_Glyph(ttface->glyph,FT_RENDER_MODE_NORMAL))return false; + _w=slot->advance.x>>6;_h=3*slot->bitmap.rows-2*slot->bitmap_top; + rw=slot->bitmap.width;rh=slot->bitmap.rows; + xofs=slot->bitmap_left;yofs=slot->bitmap.rows-slot->bitmap_top; + quad.tex=sm->smTextureCreate(rw?rw:1,rh?rh:1); + DWORD* px=sm->smTextureLock(quad.tex,0,0,rw?rw:1,rh?rh:1,false); + memset(px,0,sizeof(DWORD)*(rw?rw:1)*(rh?rh:1)); + int ptr=0; + for(int i=0;i<rh;++i) + for(int j=0;j<rw;++j) + { +#ifdef _D3D + px[i*rw+j]=ARGB(slot->bitmap.buffer[ptr],255,255,255); +#else + px[(rh-i-1)*rw+j]=ARGB(slot->bitmap.buffer[ptr],255,255,255); +#endif + ++ptr; + } + sm->smTexutreUnlock(quad.tex); + quad.blend=BLEND_ALPHABLEND; + quad.v[0].tx=0;quad.v[0].ty=0;quad.v[1].tx=1;quad.v[1].ty=0; + quad.v[2].tx=1;quad.v[2].ty=1;quad.v[3].tx=0;quad.v[3].ty=1; + return true; +} +void smTTChar::render(float x,float y,DWORD col) +{ + for(int i=0;i<4;++i)quad.v[i].col=col,quad.v[i].z=.5; + quad.v[0].x=x+xofs;quad.v[0].y=y-rh+yofs; + quad.v[1].x=x+rw+xofs;quad.v[1].y=y-rh+yofs; + quad.v[2].x=x+rw+xofs;quad.v[2].y=y+yofs; + quad.v[3].x=x+xofs;quad.v[3].y=y+yofs; + sm->smRenderQuad(&quad); +} + +bool smTTFont::loadTTF(const char* path,int pt) +{ + if(FT_Init_FreeType(&ftlib))return false; + if(FT_New_Face(ftlib,path,0,&ttface))return false; + if(FT_Set_Char_Size(ttface,0,pt*64,96,96))return false; + chars.clear(); + return true; +} +bool smTTFont::loadTTFFromMemory(char* ptr,DWORD size,int pt) +{ + if(FT_Init_FreeType(&ftlib))return false; + if(FT_New_Memory_Face(ftlib,(const FT_Byte*)ptr,(FT_Long)size,0,&ttface))return false; + if(FT_Set_Char_Size(ttface,0,pt*64,96,96))return false; + chars.clear(); + return true; +} +void smTTFont::releaseTTF() +{ + FT_Done_Face(ttface); + FT_Done_FreeType(ftlib); +} +void smTTFont::updateString(const wchar_t *format,...) +{ + memset(buf,0,sizeof(buf)); + va_list vl; + va_start(vl,format); + vswprintf(buf,1024,format,vl); + va_end(vl); + buf[1024]='\0'; + w=h=0;float lh=0; + for(int i=0;buf[i]!='\0';++i) + { + if(chars.find(buf[i])==chars.end()&&buf[i]!=L'\n') + if(!chars[buf[i]].setChar(buf[i],ttface)) + chars.erase(chars.find(buf[i])); + if(chars.find(buf[i])!=chars.end()) + { + w+=chars[buf[i]].w(); + if(chars[buf[i]].h()>lh)lh=chars[buf[i]].h(); + } + if(buf[i]==L'\n')h+=lh,lh=0; + } + h+=lh; +} +void smTTFont::render(float x,float y,DWORD col,int align) +{ + float curx,cury,lh; + if(align==ALIGN_LEFT) + { + curx=x;cury=y;lh=0; + for(int i=0;buf[i]!=L'\0';++i) + { + if(buf[i]!=L'\n') + { + if(chars.find(buf[i])!=chars.end()) + { + chars[buf[i]].render(curx,cury,col); + curx+=chars[buf[i]].w(); + lh=chars[buf[i]].h()>lh?chars[buf[i]].h():lh; + } + } + else cury+=lh,lh=0,curx=x; + } + } + if(align==ALIGN_RIGHT) + { + curx=x;cury=y;lh=0; + for(int i=wcslen(buf)-1;i>=0;--i) + { + if(buf[i]!=L'\n') + { + if(chars.find(buf[i])!=chars.end()) + { + chars[buf[i]].render(curx,cury,col); + curx-=chars[buf[i]].w(); + lh=chars[buf[i]].h()>lh?chars[buf[i]].h():lh; + } + } + else cury-=lh,lh=0,curx=x; + } + } +} +DWORD smTTFont::getCacheSize(){return chars.size();} +void smTTFont::clearCache() +{ + for(std::map<wchar_t,smTTChar>::iterator i=chars.begin();i!=chars.end();++i) + i->second.free(); + chars.clear(); +} |