📄 lightengine.cpp
字号:
#include "../../lib/Fly3D.h"
#include "lightengine.h"
#include "Commctrl.h"
#include <malloc.h>
#include <search.h>
#include <assert.h>
#define LIGHT_FACTOR 5000
#define ANGLE_THRESHOLD 0.99f
#define PLANE_THRESHOLD 0.1f
extern int lightvalue, mapsize;
extern int ambient,connectivity;
extern HDC hdc;
extern float lightradius,lmpixelsize;
extern HWND hWndHC,hWndProgress,hWndStatus;
void HC_CreateWindow();
static_mesh *lightEngine::get_object(bsp_node *n)
{
bsp_object *e=n->elem;
while(e)
{
if (e->type==TYPE_STATIC_MESH)
break;
e=e->next_elem;
}
return (static_mesh *)e;
}
void lightEngine::light(char *f)
{
char str[256],file[256];
strcpy(file,f);
strlwr(file);
GetPrivateProfileString("fly","bspfile","",bspfile,255,f);
strcpy(flydatapath,f);
if (strrchr(flydatapath,'/'))
*(strrchr(flydatapath,'/')+1)=0;
else if (strrchr(flydatapath,'\\'))
*(strrchr(flydatapath,'\\')+1)=0;
SetWindowText(hWndStatus,"Loading bsp...");
strcpy(str,flydatapath);
strcat(str,bspfile);
strcat(str,".bsp");
load_bsp(str);
if (bsp)
{
SetWindowText(hWndStatus,"Sorting bsp faces...");
sort_faces(bsp);
SetWindowText(hWndStatus,"Saving bsp ...");
save_bsp(str);
SetWindowText(hWndStatus,"Creating lightmaps...");
create_lightmaps();
SetWindowText(hWndStatus,"Saving lightmaps...");
strcpy(str,flydatapath);
strcat(str,bspfile);
strcat(str,".lmp");
save_lightmaps(str);
sprintf(str, "%i", ambient);
WritePrivateProfileString("fly", "amblight", str, f);
sprintf(str, "%f", lmpixelsize);
WritePrivateProfileString("fly", "lmpxsize", str, f);
sprintf(str, "%i", shadows);
WritePrivateProfileString("fly", "shadows", str, f);
sprintf(str, "%i", mapsize);
WritePrivateProfileString("fly", "mapsize", str, f);
strcpy(str,flyengine->flysdkpath);
strcat(str,"data\\");
int len=strlen(str);
if (strncmp(file,str,len)==0)
{
SetWindowText(hWndStatus,"Loading level...");
open_fly_file(&file[len]);
}
if (flyfile[0]!=0)
{
SetWindowText(hWndStatus,"Lighting level...");
light_lightmaps();
SetWindowText(hWndStatus,"Saving lightmaps ...");
strcpy(str,flydatapath);
strcat(str,bspfile);
strcat(str,".lmp");
save_lightmaps(str);
SetWindowText(hWndStatus,"Saving level script ...");
strcpy(str,flyfile);
save_fly_file(str);
SetWindowText(hWndStatus,"Done.");
}
else
SetWindowText(hWndStatus,"Error loading level.");
}
else
SetWindowText(hWndStatus,"Error loading bsp.");
SendMessage(hWndProgress,PBM_SETPOS,0,0);
}
void lightEngine::clear_lightmaps(unsigned char pixel_light)
{
int i;
for( i=0;i<nlmpic;i++ )
memset(lmpic[i]->bmp,0,lmpic[i]->bytesxy);
for( i=0;i<nlm;i++ )
{
memset(lm[i]->bmp,pixel_light,lm[i]->bytesxy);
lm[i]->save(lmpic[lm[i]->pic]);
}
}
int lightEngine::compute_facelist(int facenum,int *facelist)
{
int i,j,n=0,p=1;
for( i=0;i<nfaces;i++ )
if (faces[i].indx &&
faces[i].lm==-1 &&
faces[i].texpic!=-1 &&
fabs(faces[i].d0-faces[facenum].d0)<PLANE_THRESHOLD &&
vec_dot(faces[i].normal,faces[facenum].normal)>ANGLE_THRESHOLD)
facelist[n++]=i;
if (connectivity==0)
return n;
for( i=0;i<n;i++ )
{
if (i>=p || p>=n)
break;
for( j=p;j<n;j++ )
{
if (faces[facelist[j]].vert[0]==faces[facelist[i]].vert[0] ||
faces[facelist[j]].vert[0]==faces[facelist[i]].vert[1] ||
faces[facelist[j]].vert[0]==faces[facelist[i]].vert[2] ||
faces[facelist[j]].vert[1]==faces[facelist[i]].vert[0] ||
faces[facelist[j]].vert[1]==faces[facelist[i]].vert[1] ||
faces[facelist[j]].vert[1]==faces[facelist[i]].vert[2] ||
faces[facelist[j]].vert[2]==faces[facelist[i]].vert[0] ||
faces[facelist[j]].vert[2]==faces[facelist[i]].vert[1] ||
faces[facelist[j]].vert[2]==faces[facelist[i]].vert[2])
{
int swap=facelist[p];
facelist[p]=facelist[j];
facelist[j]=swap;
p++;
}
}
}
return p;
}
boundbox lightEngine::compute_bbox(int *facelist,int nf)
{
int i,j;
boundbox bb;
bb.reset();
for( i=0;i<nf;i++ )
for( j=0;j<3;j++ )
bb.add_point(*faces[facelist[i]].vert[j]);
return bb;
}
void lightEngine::compute_lightmaps()
{
if (nfaces==0)
return;
int i,j,l,nf;
boundbox bb;
for( i=0;i<nfaces;i++ )
faces[i].lm=-1;
SetWindowText(hWndStatus,"Computing lightmaps ...");
SendMessage(hWndProgress,PBM_SETRANGE,0,MAKELPARAM(0,nfaces));
SendMessage(hWndProgress,PBM_SETPOS,0,0);
int *facelist=new int[nfaces];
for( i=0;i<nfaces;i++,SendMessage(hWndProgress,PBM_SETPOS,i,0) )
if (faces[i].indx &&
faces[i].lm==-1 &&
faces[i].texpic!=-1)
{
nf=compute_facelist(i,facelist);
bb=compute_bbox(facelist,nf);
l=compute_lightmap_uv(bb,facelist,nf);
for( j=0;j<nf;j++ )
faces[facelist[j]].lm=l;
}
delete facelist;
retb r;
struct reta *rl=new struct reta[nlm];
for(i=0;i<nlm; i++)
{
rl[i].sizex=lm[i]->sizex;
rl[i].sizey=lm[i]->sizey;
r.add(&rl[i]);
}
nlmpic=r.calc(mapsize, mapsize);
for(i=0; i<nlm; i++)
{
lm[i]->offsetx=rl[i].offsetx;
lm[i]->offsety=rl[i].offsety;
lm[i]->pic=rl[i].offsetz;
}
delete rl;
for(i=0; i<nlmpic; i++) lmpic[i]=new light_map_pic(mapsize, mapsize);
for(i=0; i<nfaces; i++)
{
l=faces[i].lm;
if(l!=-1)
for(j=0; j<3; j++)
{
faces[i].lmuv[j][0]=(faces[i].lmuv[j][0]*lm[l]->sizex+lm[l]->offsetx)/mapsize;
faces[i].lmuv[j][1]=(faces[i].lmuv[j][1]*lm[l]->sizey+lm[l]->offsety)/mapsize;
}
}
for(i=0;i<nlm; i++)
lm[i]->set_base(&faces[lm[i]->facenum],lmpic[lm[i]->pic]);
}
int lightEngine::compute_lightmap_uv(boundbox bb,int *facelist,int nf)
{
int ui,vi,i,j;
vector v,diag;
float uv;
int l;
int sizex, sizey;
diag=faces[facelist[0]].normal;
i=(fabs(diag[0])>fabs(diag[1]))?0:1;
i=(fabs(diag[i])>fabs(diag[2]))?i:2;
if (i==0)
{ ui=1; vi=2; }
else if (i==1)
{ ui=0; vi=2; }
else { ui=0; vi=1; }
diag=bb.max-bb.min;
l=nlm++;
sizex=(int)(diag[ui]/lmpixelsize);
sizey=(int)(diag[vi]/lmpixelsize);
lm[l]=new light_map(-1, -1, 0, 0, sizex<=mapsize?sizex:mapsize, sizey<=mapsize?sizey:mapsize);
for( i=0;i<nf;i++ )
for( j=0;j<3;j++ )
{
v=*faces[facelist[i]].vert[j] - bb.min;
uv=v[ui]/diag[ui];
if (lm[l]->sizex>1)
uv=uv*(lm[l]->sizex-1)/lm[l]->sizex+1.0f/(lm[l]->sizex*2);
faces[facelist[i]].lmuv[j][0]=uv;
uv=v[vi]/diag[vi];
if (lm[l]->sizey>1)
uv=uv*(lm[l]->sizey-1)/lm[l]->sizey+1.0f/(lm[l]->sizey*2);
faces[facelist[i]].lmuv[j][1]=uv;
}
lm[l]->facenum=facelist[0];
return l;
}
void lightEngine::apply_light(bsp_node *n,vector& pos,vector& color,float rad)
{
if (n->child[0]==0 && n->child[1]==0)
{
static_mesh *o=get_object(n);
if (o)
{
int i;
for( i=0;i<o->objmesh->nf;i++ )
if (o->objmesh->faces[i]->lm!=-1)
{
if (lm[o->objmesh->faces[i]->lm]->lastupdate==0)
lm[o->objmesh->faces[i]->lm]->illum(pos,color,rad,shadows);
lm[o->objmesh->faces[i]->lm]->lastupdate=1;
}
}
return;
}
static float dist;
dist=n->distance(pos);
if (fabs(dist)<rad)
{
if (n->child[0])
apply_light(n->child[0],pos,color,rad);
if (n->child[1])
apply_light(n->child[1],pos,color,rad);
}
else
if (dist>0)
if (n->child[0])
apply_light(n->child[0],pos,color,rad);
else ;
else if (n->child[1])
apply_light(n->child[1],pos,color,rad);
}
void lightEngine::mark_used_bsp_faces(bsp_node *n)
{
if (n->child[0]==0 && n->child[1]==0)
{
static_mesh *o=get_object(n);
if (o)
{
int i;
for( i=0;i<o->objmesh->nf;i++ )
o->objmesh->faces[i]->indx=1;
}
}
else
{
if (n->child[0])
mark_used_bsp_faces(n->child[0]);
if (n->child[1])
mark_used_bsp_faces(n->child[1]);
}
}
void lightEngine::create_lightmaps()
{
SendMessage(hWndProgress,PBM_SETPOS,0,0);
SetWindowText(hWndStatus,"Creating ligthmaps ...");
int i;
for( i=0;i<nfaces;i++ )
faces[i].indx=0;
mark_used_bsp_faces(bsp);
compute_lightmaps();
clear_lightmaps(ambient);
}
void lightEngine::light_lightmaps()
{
int i,j,k,n;
vector v1,v2,c,pos,color;
int nlmp=0;
for( i=0;i<nlm;i++ )
nlmp+=lm[i]->sizex*lm[i]->sizey;
SendMessage(hWndProgress,PBM_SETRANGE,0,MAKELPARAM(0,nfaces));
SendMessage(hWndProgress,PBM_SETPOS,0,0);
char str[256];
sprintf(str,"Rendering level lights ( %i lm / %i pixels ) ...",nlm,nlmp);
SetWindowText(hWndStatus,str);
for( i=0;i<nfaces;i++,SendMessage(hWndProgress,PBM_SETPOS,i,0) )
if (faces[i].indx)
if (faces[i].emmradius)
{
color=faces[i].color;
if (lightvalue!=-1)
{
color.normalize();
color*=lightvalue/255.0f;
}
v1=*faces[i].vert[1]-*faces[i].vert[0];
v2=*faces[i].vert[2]-*faces[i].vert[0];
c.cross(v1,v2);
n=(int)(c.length()/LIGHT_FACTOR)+1;
for( k=0;k<n;k++ )
{
for( j=0;j<nlm;j++ )
lm[j]->lastupdate=0;
float r1=(rand()%10000)/10000.0f;
float r2=(rand()%10000)/10000.0f;
pos =
*faces[i].vert[0] + v1*r1 + v2*r2 +
faces[i].normal*10;
if (lightradius)
apply_light(bsp,pos,color,(float)lightradius);
else apply_light(bsp,pos,color,faces[i].emmradius);
}
}
bsp_object *obj=active_obj0;
i=0;
while(obj)
{
i++;
obj=(bsp_object *)obj->next_obj;
}
sprintf(str,"Rendering object lights ( %i lm / %i pixels ) ...",nlm,nlmp);
SendMessage(hWndProgress,PBM_SETRANGE,0,MAKELPARAM(0,i));
SendMessage(hWndProgress,PBM_SETPOS,0,0);
obj=active_obj0;
i=0;
while(obj)
{
obj->message(vector(0,0,0),0,FLYOBJM_STATICILLUM,0,0);
SendMessage(hWndProgress,PBM_SETPOS,++i,0);
obj=(bsp_object *)obj->next_obj;
}
for( i=0;i<nlm;i++ )
lm[i]->save(lmpic[lm[i]->pic]);
}
void lightEngine::sort_faces(bsp_node *n)
{
if (n->child[0]==0 && n->child[1]==0)
{
static_mesh *o=get_object(n);
if (o)
{
int i=0,j;
while(i<o->objmesh->nf)
{
for( j=i+1;j<o->objmesh->nf;j++ )
if (o->objmesh->faces[i]->texpic==o->objmesh->faces[j]->texpic)
{
face *f=o->objmesh->faces[j];
o->objmesh->faces[j]=o->objmesh->faces[i+1];
o->objmesh->faces[i+1]=f;
i++;
}
i++;
}
}
return;
}
if (n->child[0])
sort_faces(n->child[0]);
if (n->child[1])
sort_faces(n->child[1]);
}
int ordenar_por_area_desc(const void *elem1, const void *elem2)
{
struct reta *r1, *r2;
r1=*(struct reta **)elem1;
r2=*(struct reta **)elem2;
return r2->sizex*r2->sizey-r1->sizex*r1->sizey;
}
retb::retb()
{
nl=0;
l=(struct reta **)malloc(0);
}
retb::~retb()
{
free(l);
}
void retb::add(struct reta *r)
{
l=(struct reta **)realloc(l, (++nl)*sizeof(struct reta *));
l[nl-1]=r;
}
int retb::calc(int max_sx, int max_sy)
{
struct reta r;
r.sizex=max_sx;
r.sizey=max_sy;
r.offsetx=0;
r.offsety=0;
r.offsetz=0;
for(int i=0; i<nl; i++) l[i]->offsetz=-1;
qsort((void *)l, (size_t)nl, sizeof(struct reta *), ordenar_por_area_desc);
while(arrumar(&r)) r.offsetz++;
return r.offsetz;
}
bool retb::arrumar(struct reta *rp)
{
int i, dsx, dsy;
struct reta r[2];
if((i=procura(rp->sizex, rp->sizey))==nl) return false;
l[i]->offsetx=rp->offsetx;
l[i]->offsety=rp->offsety;
l[i]->offsetz=rp->offsetz;
dsx=rp->sizex-l[i]->sizex;
dsy=rp->sizey-l[i]->sizey;
if(dsx*rp->sizey>dsy*rp->sizex)
{
r[0].sizex=dsx;
r[0].sizey=rp->sizey;
r[0].offsetx=rp->offsetx+l[i]->sizex;
r[0].offsety=rp->offsety;
r[0].offsetz=rp->offsetz;
r[1].sizex=l[i]->sizex;
r[1].sizey=dsy;
r[1].offsetx=rp->offsetx;
r[1].offsety=rp->offsety+l[i]->sizey;
r[1].offsetz=rp->offsetz;
}
else
{
r[0].sizex=rp->sizex;
r[0].sizey=dsy;
r[0].offsetx=rp->offsetx;
r[0].offsety=rp->offsety+l[i]->sizey;
r[0].offsetz=rp->offsetz;
r[1].sizex=dsx;
r[1].sizey=l[i]->sizey;
r[1].offsetx=rp->offsetx+l[i]->sizex;
r[1].offsety=rp->offsety;
r[1].offsetz=rp->offsetz;
}
for(i=0; i<2; i++) arrumar(&r[i]);
return true;
}
int retb::procura(int sx, int sy)
{
int i;
for(i=0;i<nl;i++)
if(l[i]->offsetz==-1 &&
l[i]->sizex<=sx && l[i]->sizey<=sy)
break;
return i;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -