//========= Copyright Valve Corporation, All rights reserved. ============// // $Id$ #include "raytrace.h" #include static uint32 MapDistanceToPixel(float t) { if (t<0) return 0xffff0000; if (t>100) return 0xff000000; int a=t*1000; a&=0xff; int b=t*10; b &=0xff; int c=t*.01; c &=0xff; return 0xff000000+(a<<16)+(b<<8)+c; } #define IGAMMA (1.0/2.2) #define MAGIC_NUMBER (1<<23) static fltx4 Four_MagicNumbers={ MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER }; static ALIGN16 int32 Four_255s[4]= {0xff,0xff,0xff,0xff}; #define PIXMASK ( * ( reinterpret_cast< fltx4 *>( &Four_255s ) ) ) void MapLinearIntensities(FourVectors const &intens,uint32 *p1, uint32 *p2, uint32 *p3, uint32 *p4) { // convert four pixels worth of sse-style rgb into argb lwords // NOTE the _mm_empty macro is voodoo. do not mess with this routine casually - simply throwing // anything that ends up generating a fpu stack references in here would be bad news. static fltx4 pixscale={255.0,255.0,255.0,255.0}; fltx4 r,g,b; r=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.x,IGAMMA))); g=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.y,IGAMMA))); b=MinSIMD(pixscale,MulSIMD(pixscale,PowSIMD(intens.z,IGAMMA))); // now, convert to integer r=AndSIMD( AddSIMD( r, Four_MagicNumbers ), PIXMASK ); g=AndSIMD( AddSIMD( g, Four_MagicNumbers ), PIXMASK ); b=AndSIMD( AddSIMD( b, Four_MagicNumbers ), PIXMASK ); *(p1)=(SubInt(r, 0))|(SubInt(g, 0)<<8)|(SubInt(b, 0)<<16); *(p2)=(SubInt(r, 1))|(SubInt(g, 1)<<8)|(SubInt(b, 1)<<16); *(p3)=(SubInt(r, 2))|(SubInt(g, 2)<<8)|(SubInt(b, 2)<<16); *(p4)=(SubInt(r, 3))|(SubInt(g, 3)<<8)|(SubInt(b, 3)<<16); } static ALIGN16 uint32 signmask[4]={0x80000000,0x80000000,0x80000000,0x80000000}; static ALIGN16 int32 all_ones[4]={-1,-1,-1,-1}; static fltx4 all_zeros={0,0,0,0}; static fltx4 TraceLimit={1.0e20,1.0e20,1.0e20,1.0e20}; void RayTracingEnvironment::RenderScene( int width, int height, // width and height of desired rendering int stride, // actual width in pixels of target buffer uint32 *output_buffer, // pointer to destination Vector CameraOrigin, // eye position Vector ULCorner, // word space coordinates of upper left // monitor corner Vector URCorner, // top right corner Vector LLCorner, // lower left Vector LRCorner, // lower right RayTraceLightingMode_t lmode) { // first, compute deltas Vector dxvector=URCorner; dxvector-=ULCorner; dxvector*=(1.0/width); Vector dxvectortimes2=dxvector; dxvectortimes2+=dxvector; Vector dyvector=LLCorner; dyvector-=ULCorner; dyvector*=(1.0/height); // block_offsets-relative offsets for eahc of the 4 pixels in the block, in sse format FourVectors block_offsets; block_offsets.LoadAndSwizzle(Vector(0,0,0),dxvector,dyvector,dxvector+dyvector); FourRays myrays; myrays.origin.DuplicateVector(CameraOrigin); // tmprays is used fo rthe case when we cannot trace 4 rays at once. FourRays tmprays; tmprays.origin.DuplicateVector(CameraOrigin); // now, we will ray trace pixels. we will do the rays in a 2x2 pattern for(int y=0;y=0) { surf_colors.X(i)=TriangleColors[rslt.HitIds[i]].x; surf_colors.Y(i)=TriangleColors[rslt.HitIds[i]].y; surf_colors.Z(i)=TriangleColors[rslt.HitIds[i]].z; } } FourVectors surface_pos=myrays.direction; surface_pos*=rslt.HitDistance; surface_pos+=myrays.origin; switch(lmode) { case DIRECT_LIGHTING: { // light all points for(int l=0;l0) { l1.m_Color*=area_of_virtual_light/M_PI; l1.m_Range=0.0; l1.m_Falloff=1.0; l1.m_Attenuation0=1.0; l1.m_Attenuation1=0.0; l1.m_Attenuation2=1.0; // intens falls off as 1/r^2 l1.m_Theta=0; l1.m_Phi=M_PI; l1.RecalculateDerivedValues(); LightList.AddToTail(l1); } } } } } } } static unsigned int GetSignMask(Vector const &v) { unsigned int ret=0; if (v.x<0.0) ret++; if (v.y<0) ret+=2; if (v.z<0) ret+=4; return ret; } inline void RayTracingEnvironment::FlushStreamEntry(RayStream &s,int msk) { assert(msk>=0); assert(msk<8); fltx4 tmax=s.PendingRays[msk].direction.length(); fltx4 scl=ReciprocalSaturateSIMD(tmax); s.PendingRays[msk].direction*=scl; // normalize RayTracingResult tmpresult; Trace4Rays(s.PendingRays[msk],Four_Zeros,tmax,msk,&tmpresult); // now, write out results for(int r=0;r<4;r++) { RayTracingSingleResult *out=s.PendingStreamOutputs[msk][r]; out->ray_length=SubFloat( tmax, r ); out->surface_normal.x=tmpresult.surface_normal.X(r); out->surface_normal.y=tmpresult.surface_normal.Y(r); out->surface_normal.z=tmpresult.surface_normal.Z(r); out->HitID=tmpresult.HitIds[r]; out->HitDistance=SubFloat( tmpresult.HitDistance, r ); } s.n_in_stream[msk]=0; } void RayTracingEnvironment::AddToRayStream(RayStream &s, Vector const &start,Vector const &end, RayTracingSingleResult *rslt_out) { Vector delta=end; delta-=start; int msk=GetSignMask(delta); assert(msk>=0); assert(msk<8); int pos=s.n_in_stream[msk]; assert(pos<4); s.PendingRays[msk].origin.X(pos)=start.x; s.PendingRays[msk].origin.Y(pos)=start.y; s.PendingRays[msk].origin.Z(pos)=start.z; s.PendingRays[msk].direction.X(pos)=delta.x; s.PendingRays[msk].direction.Y(pos)=delta.y; s.PendingRays[msk].direction.Z(pos)=delta.z; s.PendingStreamOutputs[msk][pos]=rslt_out; if (pos==3) { FlushStreamEntry(s,msk); } else s.n_in_stream[msk]++; } void RayTracingEnvironment::FinishRayStream(RayStream &s) { for(int msk=0;msk<8;msk++) { int cnt=s.n_in_stream[msk]; if (cnt) { // fill in unfilled entries with dups of first for(int c=cnt;c<4;c++) { s.PendingRays[msk].origin.X(c) = s.PendingRays[msk].origin.X(0); s.PendingRays[msk].origin.Y(c) = s.PendingRays[msk].origin.Y(0); s.PendingRays[msk].origin.Z(c) = s.PendingRays[msk].origin.Z(0); s.PendingRays[msk].direction.X(c) = s.PendingRays[msk].direction.X(0); s.PendingRays[msk].direction.Y(c) = s.PendingRays[msk].direction.Y(0); s.PendingRays[msk].direction.Z(c) = s.PendingRays[msk].direction.Z(0); s.PendingStreamOutputs[msk][c]=s.PendingStreamOutputs[msk][0]; } FlushStreamEntry(s,msk); } } }