626 lines
17 KiB
C++
626 lines
17 KiB
C++
#ifndef WDL_NO_DEFINE_MINMAX
|
|
#define WDL_NO_DEFINE_MINMAX
|
|
#endif
|
|
#include "lice.h"
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include "../projectcontext.h"
|
|
#include "../lineparse.h"
|
|
#include "../ptrlist.h"
|
|
#include "../assocarray.h"
|
|
|
|
#define PI 3.1415926535897932384626433832795
|
|
|
|
static inline int chartohex(char c)
|
|
{
|
|
if (c >= '0' && c<='9') return c-'0';
|
|
else if (c>='A' && c<='F') return 10 + c - 'A';
|
|
else if (c>='a' && c<='f') return 10 + c - 'a';
|
|
return -1;
|
|
}
|
|
static int __boolval(const char *p, int defval)
|
|
{
|
|
if (!stricmp(p,"yes") ||
|
|
!stricmp(p,"true") ||
|
|
!stricmp(p,"on") ||
|
|
atoi(p)>0) return 1;
|
|
if (!stricmp(p,"no") ||
|
|
!stricmp(p,"false") ||
|
|
!stricmp(p,"off") ||
|
|
!stricmp(p,"0")) return 0;
|
|
return defval;
|
|
}
|
|
|
|
static LICE_pixel __colorval(const char *p, LICE_pixel def)
|
|
{
|
|
const size_t lp = strlen(p);
|
|
if (lp == 3)
|
|
{
|
|
int r = chartohex(p[0]);
|
|
int g = chartohex(p[1]);
|
|
int b = chartohex(p[2]);
|
|
if (r>=0&&g>=0&&b>=0)
|
|
def = LICE_RGBA(r+(r<<4),g+(g<<4),b+(b<<4),255);
|
|
}
|
|
else if (lp == 6||lp==8)
|
|
{
|
|
int r = chartohex(p[0]), r2 = chartohex(p[1]);
|
|
int g = chartohex(p[2]), g2 = chartohex(p[3]);
|
|
int b = chartohex(p[4]), b2 = chartohex(p[5]);
|
|
int a = 0xf, a2=0xf;
|
|
if (lp==8) { a=chartohex(p[6]); a2=chartohex(p[7]); }
|
|
if (r>=0&&g>=0&&b>=0&&r2>=0&&g2>=0&&b2>=0&&a>=0&&a2>=0)
|
|
def = LICE_RGBA((r<<4)+r2,(g<<4)+g2,(b<<4)+b2,(a<<4)+a2);
|
|
}
|
|
return def;
|
|
}
|
|
|
|
class lvgRenderState
|
|
{
|
|
public:
|
|
lvgRenderState()
|
|
{
|
|
m_color=LICE_RGBA(255,255,255,255);
|
|
m_alpha=1.0f;
|
|
m_blend = LICE_BLIT_MODE_COPY;
|
|
m_aa = false;
|
|
}
|
|
~lvgRenderState() { }
|
|
|
|
LICE_pixel m_color;
|
|
float m_alpha;
|
|
int m_blend;
|
|
bool m_aa;
|
|
|
|
WDL_TypedBuf<bool> m_aa_stack;
|
|
WDL_TypedBuf<float> m_alpha_stack;
|
|
WDL_TypedBuf<LICE_pixel> m_color_stack;
|
|
WDL_TypedBuf<int> m_blend_stack;
|
|
|
|
/////////
|
|
|
|
void parsealpha(const char *p)
|
|
{
|
|
int idx=0;
|
|
if (*p == '-') idx++;
|
|
if (p[idx] == '.' || (p[idx] >= '0' && p[idx] <= '9'))
|
|
m_alpha = (float)atof(p);
|
|
}
|
|
|
|
void parseaa(const char *p)
|
|
{
|
|
int a = __boolval(p,-1);
|
|
if (a>=0) m_aa = !!a;
|
|
}
|
|
|
|
void parseblend(const char *p)
|
|
{
|
|
if (!stricmp(p,"copy")) m_blend = LICE_BLIT_MODE_COPY;
|
|
else if (!stricmp(p,"add")) m_blend = LICE_BLIT_MODE_ADD;
|
|
else if (!stricmp(p,"dodge")) m_blend = LICE_BLIT_MODE_DODGE;
|
|
else if (!stricmp(p,"mul")||!stricmp(p,"multiply")) m_blend = LICE_BLIT_MODE_MUL;
|
|
else if (!stricmp(p,"overlay")) m_blend = LICE_BLIT_MODE_MUL;
|
|
else if (!stricmp(p,"hsvadj")) m_blend = LICE_BLIT_MODE_HSVADJ;
|
|
}
|
|
|
|
void parsecolor(const char *p)
|
|
{
|
|
m_color = __colorval(p,m_color);
|
|
}
|
|
|
|
#define DEF_PUSHPOP(name,defpopval) \
|
|
void push##name() { int sz=m_##name##_stack.GetSize(); m_##name##_stack.Resize(sz+1,false)[sz] = m_##name; } \
|
|
void pop##name() { int sz = m_##name##_stack.GetSize()-1; m_##name = sz>=0 ? m_##name##_stack.Get()[sz] : defpopval; m_##name##_stack.Resize(sz,false); }
|
|
DEF_PUSHPOP(color,LICE_RGBA(0,0,0,255))
|
|
DEF_PUSHPOP(alpha,1.0f)
|
|
DEF_PUSHPOP(aa,false)
|
|
DEF_PUSHPOP(blend,LICE_BLIT_MODE_COPY)
|
|
#undef DEF_PUSHPOP
|
|
|
|
bool processAttributeLine(LineParser *lp)
|
|
{
|
|
int i,numtok=lp->getnumtokens();
|
|
switch (lp->gettoken_enum(0,"color\0"
|
|
"alpha\0"
|
|
"aa\0"
|
|
"blend\0"
|
|
"\0"))
|
|
{
|
|
#define PROCTYPE(v,name) \
|
|
case v: for (i=1;i<numtok;i++) { \
|
|
const char *p = lp->gettoken_str(i); \
|
|
if (!stricmp(p,"push")) push##name(); \
|
|
else if (!stricmp(p,"pop")) pop##name(); \
|
|
else parse##name(p); \
|
|
} \
|
|
return true;
|
|
|
|
PROCTYPE(0,color)
|
|
PROCTYPE(1,alpha)
|
|
PROCTYPE(2,aa)
|
|
PROCTYPE(3,blend)
|
|
#undef PROCTYPE
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
class lvgImageCtx
|
|
{
|
|
public:
|
|
lvgImageCtx(lvgImageCtx *par) : m_images(true,deleteThis)
|
|
{
|
|
m_in_render=false;
|
|
m_par=par;
|
|
m_cachedImage=0;
|
|
m_base_w=0;
|
|
m_base_h=0;
|
|
}
|
|
~lvgImageCtx()
|
|
{
|
|
delete m_cachedImage;
|
|
m_lines.Empty(true,free);
|
|
}
|
|
|
|
WDL_PtrList<char> m_lines;
|
|
LICE_IBitmap *m_cachedImage;
|
|
|
|
lvgImageCtx *m_par;
|
|
WDL_StringKeyedArray<lvgImageCtx *> m_images;
|
|
|
|
int m_base_w,m_base_h;
|
|
bool m_in_render;
|
|
|
|
void render(lvgRenderState *rstate, int wantw, int wanth);
|
|
|
|
private:
|
|
static void deleteThis(lvgImageCtx *t) { delete t; }
|
|
|
|
double parsecoord(const char *p, double scale, bool round)
|
|
{
|
|
if (!*p) return 0;
|
|
if (p[0] == 'a' && p[1]) return atoi(p+1);
|
|
if (p[0] == 'w')
|
|
{
|
|
scale = m_cachedImage ? m_cachedImage->getWidth() : 0.0;
|
|
p++;
|
|
}
|
|
else if (p[0] == 'h')
|
|
{
|
|
scale = m_cachedImage ? m_cachedImage->getHeight() : 0.0;
|
|
p++;
|
|
}
|
|
return atof(p) * scale + (round ? 0.5 : 0.0);
|
|
}
|
|
void processLvgLine(LineParser *lp, lvgRenderState *state, LICE_IBitmap *bm, double xscale, double yscale);
|
|
|
|
};
|
|
|
|
#define DECL_OPT(type, cfunc) \
|
|
static type getoption_##type(LineParser *lp, int startidx, const char *name, type def) { \
|
|
const size_t namelen = strlen(name); \
|
|
for(;startidx<lp->getnumtokens();startidx++) { \
|
|
const char *p=lp->gettoken_str(startidx); \
|
|
if (!strnicmp(name,p,namelen) && p[namelen]=='=') return cfunc(p+namelen+1,def); \
|
|
} \
|
|
return def; \
|
|
}
|
|
|
|
static int __intval(const char *p, int def) { return atoi(p); }
|
|
static double __dblval(const char *p, double def) { return atof(p); }
|
|
|
|
DECL_OPT(bool,!!__boolval)
|
|
DECL_OPT(int,__intval)
|
|
DECL_OPT(double,__dblval)
|
|
DECL_OPT(LICE_pixel,__colorval)
|
|
|
|
#undef DECL_OPT
|
|
|
|
void lvgImageCtx::processLvgLine(LineParser *lp, lvgRenderState *state, LICE_IBitmap *bm, double xscale, double yscale)
|
|
{
|
|
if (state->processAttributeLine(lp)) return;
|
|
|
|
int numtok = lp->getnumtokens();
|
|
const char *tok = lp->gettoken_str(0);
|
|
if (!stricmp(tok,"line"))
|
|
{
|
|
int i;
|
|
float lx,ly;
|
|
for (i = 1; i < numtok-1; i+= 2)
|
|
{
|
|
const char *p=lp->gettoken_str(i);
|
|
if (strstr(p,"=")) break;
|
|
float x=(float)parsecoord(p,xscale,false);
|
|
p=lp->gettoken_str(i+1);
|
|
if (strstr(p,"=")) break;
|
|
float y=(float)parsecoord(p,yscale,false);
|
|
|
|
if (i!=1) LICE_FLine(bm,lx,ly,x,y,state->m_color,state->m_alpha,state->m_blend,state->m_aa);
|
|
|
|
lx=x;
|
|
ly=y;
|
|
}
|
|
}
|
|
else if (!stricmp(tok,"circle"))
|
|
{
|
|
if (numtok>=4)
|
|
{
|
|
float x=(float)parsecoord(lp->gettoken_str(1),xscale,false);
|
|
float y=(float)parsecoord(lp->gettoken_str(2),yscale,false);
|
|
float r=(float)(atof(lp->gettoken_str(3))*lice_min(xscale,yscale));
|
|
if (getoption_bool(lp,1,"fill",false))
|
|
{
|
|
LICE_FillCircle(bm,x,y,r,state->m_color,state->m_alpha,state->m_blend,state->m_aa);
|
|
}
|
|
else
|
|
LICE_Circle(bm,x,y,r,state->m_color,state->m_alpha,state->m_blend,state->m_aa);
|
|
}
|
|
}
|
|
else if (!stricmp(tok,"arc"))
|
|
{
|
|
if (numtok>=6)
|
|
{
|
|
float x=(float)parsecoord(lp->gettoken_str(1),xscale,false);
|
|
float y=(float)parsecoord(lp->gettoken_str(2),yscale,false);
|
|
float r=(float)(atof(lp->gettoken_str(3))*lice_min(xscale,yscale));
|
|
float a1=(float)(atof(lp->gettoken_str(4))*PI/180.0);
|
|
float a2=(float)(atof(lp->gettoken_str(5))*PI/180.0);
|
|
LICE_Arc(bm,x,y,r,a1,a2,state->m_color,state->m_alpha,state->m_blend,state->m_aa);
|
|
}
|
|
}
|
|
else if (!stricmp(tok,"fill"))
|
|
{
|
|
if (numtok>=3) // fill x y [cmask=xxxxxx kmask=xxxxxxx]
|
|
{
|
|
LICE_pixel cmask = getoption_LICE_pixel(lp,1,"cmask",LICE_RGBA(255,255,255,0));
|
|
LICE_pixel kmask = getoption_LICE_pixel(lp,1,"kmask",LICE_RGBA(0,0,0,0));
|
|
int x = (int)parsecoord(lp->gettoken_str(1),xscale,true);
|
|
int y = (int)parsecoord(lp->gettoken_str(2),yscale,true);
|
|
|
|
LICE_SimpleFill(bm,x,y,state->m_color,cmask,kmask);
|
|
}
|
|
}
|
|
else if (!stricmp(tok,"rect"))
|
|
{
|
|
if (numtok>=5) // rect x y w h [dcdx=xxxxxxxx dcdy=xxxxxxxxx dcdxscale=1.0 dcdyscale=1.0]
|
|
{
|
|
LICE_pixel dcdx = getoption_LICE_pixel(lp,1,"dcdx",LICE_RGBA(0x80,0x80,0x80,0x80));
|
|
LICE_pixel dcdy = getoption_LICE_pixel(lp,1,"dcdy",LICE_RGBA(0x80,0x80,0x80,0x80));
|
|
double dcdxsc = getoption_double(lp,1,"dcdxscale",1.0);
|
|
double dcdysc = getoption_double(lp,1,"dcdyscale",1.0);
|
|
|
|
// todo: any options?
|
|
int x = (int)parsecoord(lp->gettoken_str(1),xscale,true);
|
|
int y = (int)parsecoord(lp->gettoken_str(2),yscale,true);
|
|
int w = (int)parsecoord(lp->gettoken_str(3),xscale,true);
|
|
int h = (int)parsecoord(lp->gettoken_str(4),yscale,true);
|
|
if (w>0 && h>0)
|
|
{
|
|
if (dcdx!=LICE_RGBA(0x80,0x80,0x80,0x80) ||
|
|
dcdy!=LICE_RGBA(0x80,0x80,0x80,0x80))
|
|
{
|
|
LICE_pixel sc = state->m_color;
|
|
dcdxsc /= w*128.0;
|
|
dcdysc /= h*128.0;
|
|
LICE_GradRect(bm,x,y,w,h,
|
|
(float)(LICE_GETR(sc)/255.0),
|
|
(float)(LICE_GETG(sc)/255.0),
|
|
(float)(LICE_GETB(sc)/255.0),
|
|
(float)(LICE_GETA(sc)/255.0*state->m_alpha),
|
|
(float)(((int)LICE_GETR(dcdx)-0x80)*dcdxsc),
|
|
(float)(((int)LICE_GETG(dcdx)-0x80)*dcdxsc),
|
|
(float)(((int)LICE_GETB(dcdx)-0x80)*dcdxsc),
|
|
(float)(((int)LICE_GETA(dcdx)-0x80)*dcdxsc),
|
|
(float)(((int)LICE_GETR(dcdy)-0x80)*dcdysc),
|
|
(float)(((int)LICE_GETG(dcdy)-0x80)*dcdysc),
|
|
(float)(((int)LICE_GETB(dcdy)-0x80)*dcdysc),
|
|
(float)(((int)LICE_GETA(dcdy)-0x80)*dcdysc),
|
|
state->m_blend);
|
|
}
|
|
else
|
|
LICE_FillRect(bm,x,y,w,h,state->m_color,state->m_alpha,state->m_blend);
|
|
}
|
|
}
|
|
}
|
|
else if (!stricmp(tok,"rerender"))
|
|
{
|
|
if (numtok>=2)
|
|
{
|
|
int forcew=getoption_int(lp,1,"w",0),forceh=getoption_int(lp,1,"h",0);
|
|
bool useState=getoption_bool(lp,1,"usestate",false);
|
|
|
|
lvgImageCtx *scan = this;
|
|
while (scan)
|
|
{
|
|
lvgImageCtx *p = scan->m_images.Get(lp->gettoken_str(1));
|
|
if (p)
|
|
{
|
|
if (!p->m_in_render)
|
|
{
|
|
p->m_in_render=true;
|
|
p->render(useState ? state : NULL,forcew,forceh);
|
|
p->m_in_render=false;
|
|
}
|
|
break;
|
|
}
|
|
scan=scan->m_par;
|
|
}
|
|
}
|
|
}
|
|
else if (!stricmp(tok,"blit"))
|
|
{
|
|
if (numtok>=3) // blit image x y [options]
|
|
{
|
|
LICE_IBitmap *src=NULL;
|
|
lvgImageCtx *scan = this;
|
|
const char *rd = lp->gettoken_str(1);
|
|
|
|
while (!strnicmp(rd,"parent:",7)) { scan = scan ? scan->m_par : NULL; rd += 7; }
|
|
|
|
if (!stricmp(rd,"parent"))
|
|
{
|
|
if (scan) scan=scan->m_par;
|
|
if (scan) src=scan->m_cachedImage;
|
|
}
|
|
else if (!stricmp(rd,"self"))
|
|
{
|
|
if (scan) src=scan->m_cachedImage;
|
|
}
|
|
else while (scan&&!src)
|
|
{
|
|
lvgImageCtx *p = scan->m_images.Get(rd);
|
|
if (p)
|
|
{
|
|
if (!p->m_cachedImage && !p->m_in_render)
|
|
{
|
|
p->m_in_render=true;
|
|
p->render(NULL,0,0);
|
|
p->m_in_render=false;
|
|
}
|
|
src = p->m_cachedImage;
|
|
break;
|
|
}
|
|
scan=scan->m_par;
|
|
}
|
|
if (src)
|
|
{
|
|
int x = (int)parsecoord(lp->gettoken_str(2),xscale,true);
|
|
int y = (int)parsecoord(lp->gettoken_str(3),yscale,true);
|
|
|
|
// these will be options filter= srcalpha= w= h= scale=
|
|
bool filter=getoption_bool(lp,1,"filter",true);
|
|
bool usesrcalpha = getoption_bool(lp,1,"srcalpha",true);
|
|
int w = getoption_int(lp,1,"w",src->getWidth());
|
|
int h = getoption_int(lp,1,"h",src->getHeight());
|
|
double sc = getoption_double(lp,1,"scale",1.0f);
|
|
if (fabs(sc-1.0)>0.0000000001)
|
|
{
|
|
w = (int)(w*sc+0.5);
|
|
h = (int)(h*sc+0.5);
|
|
}
|
|
// double ang = getoption_double(lp,1,"rotate",0.0) * PI / 180.0;
|
|
float sx=(float)getoption_double(lp,1,"srcx",0.0);
|
|
float sy=(float)getoption_double(lp,1,"srcy",0.0);
|
|
float sw=(float)getoption_double(lp,1,"srcw",src->getWidth());
|
|
float sh=(float)getoption_double(lp,1,"srch",src->getHeight());
|
|
// if (fabs(ang)>0.0001) LICE_RotatedBlit(bm,src,x,y,w,h,sx,sy,sw,sh,ang,true,state->m_alpha,state->m_blend,0,0);
|
|
//else
|
|
LICE_ScaledBlit(bm,src,x,y,w,h,sx,sy,sw,sh,
|
|
state->m_alpha,state->m_blend|(filter ? LICE_BLIT_FILTER_BILINEAR : 0)|(usesrcalpha ? LICE_BLIT_USE_ALPHA : 0));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void lvgImageCtx::render(lvgRenderState *rstate, int wantw, int wanth)
|
|
{
|
|
if (wantw<1) wantw = m_base_w;
|
|
if (wanth<1) wanth = m_base_h;
|
|
|
|
if (wantw<1||wanth<1)
|
|
{
|
|
if (m_cachedImage) m_cachedImage->resize(0,0);
|
|
return;
|
|
}
|
|
|
|
if (!m_cachedImage) m_cachedImage = new LICE_MemBitmap(wantw,wanth);
|
|
else m_cachedImage->resize(wantw,wanth);
|
|
|
|
LICE_Clear(m_cachedImage,LICE_RGBA(0,0,0,0));
|
|
|
|
lvgRenderState rs;
|
|
if (rstate) rs = *rstate;
|
|
|
|
double xscale = wantw / lice_max(m_base_w,1);
|
|
double yscale = wanth / lice_max(m_base_h,1);
|
|
int x;
|
|
bool comment_state=false;
|
|
LineParser lp(comment_state);
|
|
for (x=0;x<m_lines.GetSize();x++)
|
|
{
|
|
if (!lp.parse(m_lines.Get(x)) && lp.getnumtokens()>0)
|
|
processLvgLine(&lp,&rs,m_cachedImage,xscale,yscale);
|
|
}
|
|
}
|
|
|
|
void *LICE_GetSubLVG(void *lvg, const char *subname)
|
|
{
|
|
if (!lvg||!subname||!*subname) return NULL;
|
|
lvgImageCtx *t = (lvgImageCtx *)lvg;
|
|
return t->m_images.Get(subname);
|
|
}
|
|
|
|
LICE_IBitmap *LICE_RenderLVG(void *lvg, int reqw, int reqh, LICE_IBitmap *bmOut)
|
|
{
|
|
lvgImageCtx *t = (lvgImageCtx *)lvg;
|
|
if (!t || !t->m_lines.GetSize() || t->m_in_render) return NULL;
|
|
|
|
if (bmOut)
|
|
{
|
|
delete t->m_cachedImage;
|
|
t->m_cachedImage = bmOut;
|
|
}
|
|
else if (!t->m_cachedImage) t->m_cachedImage = new LICE_MemBitmap;
|
|
|
|
t->m_in_render=true;
|
|
t->render(NULL,reqw,reqh);
|
|
t->m_in_render=false;
|
|
|
|
LICE_IBitmap *ret = t->m_cachedImage;
|
|
|
|
t->m_cachedImage=NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void LICE_DestroyLVG(void *lvg)
|
|
{
|
|
lvgImageCtx *t = (lvgImageCtx *)lvg;
|
|
if (t && !t->m_par) delete t;
|
|
}
|
|
|
|
class lvgRdContext : public ProjectStateContext
|
|
{
|
|
public:
|
|
lvgRdContext(FILE *fp) { m_fp=fp; }
|
|
virtual ~lvgRdContext() { }
|
|
|
|
virtual void AddLine(const char *fmt, ...) {};
|
|
virtual int GetLine(char *buf, int buflen) // returns -1 on eof
|
|
{
|
|
if (!m_fp) return -1;
|
|
for (;;)
|
|
{
|
|
buf[0]=0;
|
|
fgets(buf,buflen,m_fp);
|
|
if (!buf[0]) return -1;
|
|
|
|
char *p=buf;
|
|
while (*p) p++;
|
|
while (p>buf && (p[-1] == '\r' || p[-1]=='\n')) p--;
|
|
*p=0;
|
|
if (*buf) return 0;
|
|
}
|
|
}
|
|
|
|
virtual WDL_INT64 GetOutputSize() { return 0; }
|
|
virtual int GetTempFlag() { return 0; }
|
|
virtual void SetTempFlag(int flag) {}
|
|
|
|
FILE *m_fp;
|
|
};
|
|
|
|
void *LICE_LoadLVGFromContext(ProjectStateContext *ctx, const char *nameInfo, int defw, int defh)
|
|
{
|
|
if (!ctx) return NULL;
|
|
|
|
bool err=false;
|
|
int ignoreBlockCnt=0;
|
|
|
|
lvgImageCtx *retimg = new lvgImageCtx(NULL);
|
|
lvgImageCtx *curimg = NULL;
|
|
|
|
if (nameInfo)
|
|
{
|
|
curimg = retimg;
|
|
curimg->m_base_w = defw;
|
|
curimg->m_base_h = defh;
|
|
}
|
|
|
|
while (!err)
|
|
{
|
|
char line[4096];
|
|
line[0]=0;
|
|
if (ctx->GetLine(line,sizeof(line))) break;
|
|
|
|
char *p=line;
|
|
while (*p == ' ' || *p == '\t') p++;
|
|
if (!*p) continue;
|
|
|
|
if (ignoreBlockCnt>0)
|
|
{
|
|
if (*p == '<') ignoreBlockCnt++;
|
|
else if (*p == '>') ignoreBlockCnt--;
|
|
}
|
|
else
|
|
{
|
|
if (*p == '<')
|
|
{
|
|
bool comment_state=false;
|
|
LineParser lp(comment_state);
|
|
if (!lp.parse(p)&&lp.getnumtokens()>=2 && !strcmp(lp.gettoken_str(0),"<LVG"))
|
|
{
|
|
if (!curimg)
|
|
{
|
|
// lp.gettoken_str(1) = version info string?
|
|
curimg = retimg;
|
|
}
|
|
else
|
|
{
|
|
lvgImageCtx *img = new lvgImageCtx(curimg);
|
|
curimg->m_images.Insert(lp.gettoken_str(1),img);
|
|
curimg = img;
|
|
}
|
|
curimg->m_base_w = lp.gettoken_int(2);
|
|
curimg->m_base_h = lp.gettoken_int(3);
|
|
}
|
|
else ignoreBlockCnt++;
|
|
}
|
|
else if (curimg)
|
|
{
|
|
if (*p == '>')
|
|
{
|
|
curimg = curimg->m_par;
|
|
if (!curimg) break; // success!
|
|
}
|
|
else
|
|
{
|
|
curimg->m_lines.Add(strdup(p));
|
|
}
|
|
}
|
|
|
|
if (!curimg) err=true; // <LVG must be first non-whitespace line
|
|
}
|
|
}
|
|
|
|
if (err)
|
|
{
|
|
delete retimg;
|
|
return 0;
|
|
}
|
|
return retimg;
|
|
|
|
}
|
|
|
|
void *LICE_LoadLVG(const char *filename)
|
|
{
|
|
FILE *fp=NULL;
|
|
#if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
|
|
#ifdef WDL_SUPPORT_WIN9X
|
|
if (GetVersion()<0x80000000)
|
|
#endif
|
|
{
|
|
WCHAR wf[2048];
|
|
if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,filename,-1,wf,2048))
|
|
fp = _wfopen(wf,L"rb");
|
|
}
|
|
#endif
|
|
if (!fp) fp = WDL_fopenA(filename,"rb");
|
|
|
|
if (fp)
|
|
{
|
|
lvgRdContext ctx(fp);
|
|
|
|
void *p = LICE_LoadLVGFromContext(&ctx,NULL,0,0);
|
|
|
|
fclose(fp);
|
|
|
|
return p;
|
|
}
|
|
|
|
return 0;
|
|
}
|