Redline/source/lights.cpp

236 lines
7.9 KiB
C++
Raw Normal View History

#include <OpenGL/gl.h>
#include <math.h>
#include "vectors.h"
#include "environment.h"
#include "entities.h"
#include "textures.h"
#include "renderframe.h"
#include "roads.h"
#include "collision.h"
#include "config.h"
#include "stencil.h"
#define kLightOffset 0.6
#define kLightReflectionOffset 15
void RenderEntityLights(tGameEntity *entity,int numLights,int lightFlags,float reflectionDim,tLightDefinition *lights)
{
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_CURRENT_BIT+GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_FOG_BIT);
glDepthMask(false);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glDisable(GL_FOG);
TexturesSelectTex(FileGetReference("Particle.pct"));
for(int i=0;i<numLights;i++)
//is the light on?
if(lightFlags&lights[i].onFlags&&!(lightFlags&lights[i].offFlags))
//is this a dot light? (a light which only needs a particle texture to be drawn)
if(lights[i].type!=kLightTypeSpot)
{
float visibility=-lights[i].dir*entity->dir**MatrixGetZVector(gCameraEntity->dir);
//is the light pointing towards the camera?
if(lights[i].type==kLightTypeDirectionlessDot||lights[i].type==kLightTypeDirectionlessDotReflective)
visibility=1;
else if(lights[i].type==kLightTypeSpecularDot)
visibility=sign(visibility)*powf(visibility*!((lights[i].pos*entity->dir+entity->pos)-gCameraEntity->pos)**MatrixGetZVector(gCameraEntity->dir),100);
if(visibility>0){
if(visibility>1)visibility=1;
float size=lights[i].size;
//draw particle texture
tVector3 lightPos=lights[i].pos*entity->dir+entity->pos;
float camDist=~(lightPos-gCameraEntity->pos);
tVector3 drawlightPos=lightPos-(lightPos-gCameraEntity->pos)*kLightOffset/camDist;
size*=(camDist-kLightOffset)/camDist;
SetupTranslation(drawlightPos,gCameraEntity->dir);
glColor4f(lights[i].rgb.x,lights[i].rgb.y,lights[i].rgb.z,visibility);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(size,size);
glTexCoord2d(1,0); glVertex2f(size,-size);
glTexCoord2d(0,1); glVertex2f(-size,size);
glTexCoord2d(0,0); glVertex2f(-size,-size);
glEnd();
//does the light reflect on the ground?
if(lights[i].type==kLightTypeDotRefelective||lights[i].type==kLightTypeDirectionlessDotReflective)
{
int lastRoadIndex=entity->lastRoadIndex;
int surface=-1;
lightPos=lightPos-Vector(0,GetGroundOffset(lightPos,&lastRoadIndex,NULL,&surface),0);
float camDist=~(lightPos-gCameraEntity->pos);
float size=lights[i].size;
if(camDist>2*kLightReflectionOffset)
{
drawlightPos=lightPos-(lightPos-gCameraEntity->pos)*kLightReflectionOffset/camDist;
size*=(camDist-kLightReflectionOffset)/camDist;
}
else
drawlightPos=lightPos;
//is the ground reflective
if(surface!=-1)
if(gSurfaceTypes->types[surface].reflectionEnable)
{
//draw reflection texture
SetupTranslation(drawlightPos,gCameraEntity->dir);
if(camDist<=2*kLightReflectionOffset)
glDisable(GL_DEPTH_TEST);
visibility*=1-reflectionDim*0.6;
glColor4f(lights[i].rgb.x,lights[i].rgb.y,lights[i].rgb.z,visibility);
TexturesSelectTex(FileGetReference("lightreflection.pct"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(size,size);
glTexCoord2d(1,0); glVertex2f(size,-5*size);
glTexCoord2d(0,1); glVertex2f(-size,size);
glTexCoord2d(0,0); glVertex2f(-size,-5*size);
glEnd();
TexturesSelectTex(FileGetReference("Particle.pct"));
#ifdef __POLYCOUNT
gPolyCount+=2;
#endif
glEnable(GL_DEPTH_TEST);
}
}
#ifdef __POLYCOUNT
gPolyCount+=2;
#endif
}
}
glPopAttrib();
}
#define kConeSections 16
#define kConeLength 6.5
void DrawLightCone(float scale)
{
tVector3 c[kConeSections];
for(int i=0;i<kConeSections;i++)
c[i]=Vector(cos((2*PI*i)/kConeSections)*gStencilZoom,sin((2*PI*i)/kConeSections)*gStencilZoom,4)*scale*gStencilZoom;
for(int i=0;i<kConeSections;i++)
{
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(0,0,(1-gStencilZoom)*10);
glVertex3fv(&c[i].x);
glVertex3fv(&c[(i+1)%kConeSections].x);
glVertex3f(0,0,kConeLength*scale);
glEnd();
}
#ifdef __POLYCOUNT
gPolyCount+=2*kConeSections;
#endif
}
void DrawLightConeClippedFar(float scale,float clipPlanePos,tVector3 clipPlaneNormal)
{
tVector3 c[kConeSections];
tVector3 clipPos=Vector(0,0,kConeLength*scale*clipPlanePos);
float baseClipDist=-clipPos*clipPlaneNormal;
float cClipDist;
for(int i=0;i<kConeSections;i++)
c[i]=Vector(cos((2*PI*i)/kConeSections)*gStencilZoom,sin((2*PI*i)/kConeSections)*gStencilZoom,4)*scale*gStencilZoom;
for(int i=0;i<kConeSections;i++)
if((cClipDist=((c[i]-clipPos)*clipPlaneNormal))>0)
{
float cClipPos=(1-(cClipDist/(cClipDist-baseClipDist)));
if(cClipPos<=0)return;
c[i]=c[i]*cClipPos;
}
for(int i=0;i<kConeSections;i++)
{
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(0,0,(1-gStencilZoom)*10);
glVertex3fv(&c[i].x);
glVertex3fv(&c[(i+1)%kConeSections].x);
glVertex3f(0,0,clipPos.z);
glEnd();
}
#ifdef __POLYCOUNT
gPolyCount+=2*kConeSections;
#endif
}
void DrawLightConeClippedNear(float scale,tVector3 clipPlanePos,tVector3 clipPlaneNormal)
{
}
//draws a car's light cones (usually headlights)
void RenderEntityLightCones(tGameEntity *entity,int numLights,int lightFlags,tLightDefinition *lights)
{
glPushAttrib(GL_STENCIL_BUFFER_BIT+GL_COLOR_BUFFER_BIT+GL_POLYGON_BIT+GL_DEPTH_BUFFER_BIT+GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
for(int i=0;i<numLights;i++)
//is the light on?
if(lightFlags&lights[i].onFlags&&!(lightFlags&lights[i].offFlags))
//is it a spot light
if(lights[i].type==kLightTypeSpot)
//is stencil buffering enabled, and are spotlights enabled for this environment?
if(gConfig->stencil&&gEnvironment->spotLightEnable)
{
//translate to draw the light cone
tVector3 lightPos=lights[i].pos*entity->dir+entity->pos;
tMatrix3 m;
MatrixIdentity(m);
*MatrixGetZVector(m)=lights[i].dir;
*MatrixGetXVector(m)=!(lights[i].dir%Vector(0,1,0));
*MatrixGetYVector(m)=(lights[i].dir%*MatrixGetXVector(m));
MatrixMult(m,entity->dir,m);
SetupTranslation(lightPos,m);
//setup stencil buffer
//drawing light cones works just like stencil buffer shadow volumes
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glColorMask(0, 0, 0, 0);
glStencilFunc(GL_ALWAYS, 1, 0xffffffff);
tVector3 camDir=*MatrixGetZVector(gCameraEntity->dir);
float clip1=(lightPos-gCameraEntity->pos)*camDir;
float clip2=((lightPos+(lights[i].dir*kConeLength*lights[i].size)*entity->dir)-gCameraEntity->pos)*camDir;
//test if the light cone volume intersects the clipping volume
if(clip1>ClipDistance()&&clip2>ClipDistance())
{//clip near and far (not implemented)
}
else if(clip1>ClipDistance())
{//clip near (not implemented)
}
else if(clip2>ClipDistance()-20)
{//clip far
tMatrix3 mInv;
MatrixTranspose(m,mInv);
tVector3 clipPlaneDir=camDir*mInv;
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
DrawLightConeClippedFar(lights[i].size*gStencilZoom,(ClipDistance()-20-clip1)/(clip2-clip1),clipPlaneDir);
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
DrawLightConeClippedFar(lights[i].size*gStencilZoom,(ClipDistance()-20-clip1)/(clip2-clip1),clipPlaneDir);
}
else
{//no clip
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
DrawLightCone(lights[i].size*gStencilZoom);
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
DrawLightCone(lights[i].size*gStencilZoom);
}
}
glPopAttrib();
}