aboutsummaryrefslogtreecommitdiff
path: root/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'extensions')
-rw-r--r--extensions/smanim.cpp196
-rw-r--r--extensions/smbmfont.cpp219
-rw-r--r--extensions/smdatapack.cpp177
-rw-r--r--extensions/smentity.cpp207
-rw-r--r--extensions/smgrid.cpp111
-rw-r--r--extensions/smttfont.cpp144
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 &copy)
+{
+ memcpy(this,&copy,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 &copy)
+{
+ memcpy(this,&copy,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 &copy)
+{
+ 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 &copy)
+{
+ if(this!=&copy)
+ {
+ 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();
+}