CrystalSpace

Public API Reference

csplugincommon/softshader/types.h

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2005 by Jorrit Tyberghein
00003               (C) 2005 by Frank Richter
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public
00016     License along with this library; if not, write to the Free
00017     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 #ifndef __CS_CSPLUGINCOMMON_SOFTSHADER_TYPES_H__
00021 #define __CS_CSPLUGINCOMMON_SOFTSHADER_TYPES_H__
00022 
00027 #include "csgeom/fixed.h"
00028 
00032 namespace CS
00033 {
00034 namespace PluginCommon
00035 {
00036   namespace SoftShader
00037   {
00039     const size_t maxBuffers = 16;
00041     typedef uint BuffersMask;
00043     typedef uint TexturesMask;
00044   
00046     template <typename T>
00047     static inline T Lerp (const T& a, const T& b, float f)
00048     { return a + (b-a) * f; }
00049   
00051     struct InterpolateEdgePersp
00052     {
00054       float x;
00056       float dxdy;
00058       float Iz;
00060       float dIzdy;
00062       struct PerFloat
00063       {
00065         float Ic;
00067         float dIcdy;
00069         float c;
00070       } Floats[maxBuffers*4];
00071   
00073       void Setup (const csVector3* vertices, const float* floats, 
00074         const size_t floatNum, size_t sv, size_t fv, int sy)
00075       {
00076         const csVector3 vsv (vertices[sv]);
00077         const csVector3 vfv (vertices[fv]);
00078   
00079         float dy = vsv.y - vfv.y;
00080         if (dy)
00081         {
00082           float inv_dy = 1 / dy;
00083           x = vsv.x;
00084           dxdy = (vfv.x - x) * inv_dy;
00085           const float Isz = vsv.z; // Z coord already inverted here
00086           const float Ifz = vfv.z;
00087           dIzdy = (Ifz - Isz) * inv_dy;
00088   
00089           // horizontal pixel correction
00090           float deltaX = dxdy *
00091             (vsv.y - (float (sy) - 0.5));
00092           x += deltaX;
00093   
00094           // apply sub-pixel accuracy factor
00095           float Factor;
00096           if (vfv.x != vsv.x)
00097             Factor = deltaX / (vfv.x - vsv.x);
00098           else
00099             Factor = 0;
00100   
00101           Iz = Lerp (Isz, Ifz, Factor);
00102           const float z = 1.0f/Iz;
00103   
00104             // Z coord already inverted here
00105           const float* Icsv = floats + sv*floatNum;
00106           const float* Icfv = floats + fv*floatNum;
00107           for (size_t f = 0; f < floatNum; f++)
00108           {
00109             const float fs = *Icsv++; 
00110             const float ff = *Icfv++; 
00111             Floats[f].Ic = Lerp (fs, ff, Factor);
00112             Floats[f].c = Floats[f].Ic * z;
00113             Floats[f].dIcdy = (ff - fs) * inv_dy;
00114           }
00115         } /* endif */
00116       }
00118       void Advance (const size_t floatNum)
00119       {
00120         Iz += dIzdy;
00121         const float z = 1.0f/Iz;
00122   
00123         for (size_t f = 0; f < floatNum; f++)
00124         {
00125           Floats[f].Ic += Floats[f].dIcdy;
00126           Floats[f].c = Floats[f].Ic * z;
00127         }
00128         x += dxdy;
00129       }
00130     };
00132     struct InterpolateScanlinePerspCommon
00133     {
00135       csFixed24 Iz, dIzdx;
00137       float Iz_f, dIzdx_f, dIzdx_fLast;
00138     };
00139   
00141     struct ScanlineComp
00142     {
00144       csFixed16 c;
00146       csFixed16 dcdx;
00147     };
00149     struct ScanlineCompDivZ
00150     {
00152       float Ic;
00154       float dIcdx;
00156       float dIcdxLast;
00157     };
00158 
00160     template<int maxFloats>
00161     struct InterpolateScanlinePersp : public InterpolateScanlinePerspCommon
00162     {
00164       ScanlineComp floats[maxFloats];
00166       ScanlineCompDivZ floats_f[maxFloats];
00167   
00169       int InterpolStep;
00171       int InterpolShift;
00173       int ipx;
00175       int spans;
00177       float invLastSpan;
00178   
00180       void Setup (const InterpolateEdgePersp& L, const InterpolateEdgePersp& R,
00181         uint len, int ipolStep, int ipolShift)
00182       {
00183         // @@@ If you notice something that can be sped up, don't hesitate!
00184         InterpolStep = ipolStep;
00185         InterpolShift = ipolShift;
00186         spans = len / ipolStep;
00187 
00188         const float inv_l = 1.0f/len;
00189         const float ipf = (float)InterpolStep;
00190         ipx = InterpolStep;
00191         const float fact = inv_l * ipf;
00192         uint lastSpanSize = len % ipolStep;
00193         if (lastSpanSize == 0) lastSpanSize = ipolStep;
00194         const float lastFact = float (lastSpanSize) / ipf;
00195         invLastSpan = 1.0f / float(lastSpanSize);
00196         Iz = Iz_f = L.Iz;
00197         dIzdx = dIzdx_f = (R.Iz - L.Iz) * inv_l;
00198         dIzdx_fLast = dIzdx_f * float (lastSpanSize);
00199         dIzdx_f *= ipf;
00200         Iz_f += (spans == 0) ? dIzdx_fLast : dIzdx_f;   
00201         float z2 = 1.0f / Iz_f;
00202         for (size_t f = 0; f < maxFloats; f++)
00203         {
00204           const float cL = L.Floats[f].c;
00205           const float IcL = L.Floats[f].Ic;
00206           const float IcR = R.Floats[f].Ic;
00207           floats[f].c = cL;
00208           floats_f[f].dIcdx = (IcR - IcL) * fact;
00209           floats_f[f].dIcdxLast = floats_f[f].dIcdx * lastFact;
00210         }
00211         if (spans == 0)
00212         {
00213           for (size_t f = 0; f < maxFloats; f++)
00214           {
00215             const float cL = L.Floats[f].c;
00216             const float IcL = L.Floats[f].Ic;
00217             floats_f[f].Ic = IcL + floats_f[f].dIcdxLast;
00218             floats[f].dcdx = (floats_f[f].Ic*z2 - cL) * invLastSpan;
00219           }
00220         }
00221         else
00222         {
00223           for (size_t f = 0; f < maxFloats; f++)
00224           {
00225             const float IcL = L.Floats[f].Ic;
00226             floats_f[f].Ic = IcL + floats_f[f].dIcdx;
00227             floats[f].dcdx = (floats_f[f].Ic*z2 - floats[f].c) >> InterpolShift;
00228           }
00229         }
00230       }
00232       void Advance ()
00233       {
00234         if (--ipx > 0)
00235         {
00236           Iz += dIzdx;
00237           for (size_t f = 0; f < maxFloats; f++)
00238           {
00239             floats[f].c += floats[f].dcdx;
00240           }
00241         }
00242         else
00243         {
00244           if (--spans == 0)
00245           {
00246             dIzdx_f = dIzdx_fLast;
00247           }
00248           /* Note: Iz_f is "ahead" one interpolation span, ie when the
00249            * deltas are set up for the next, it has the value from the
00250            * beginning if that span. */
00251           const float z = 1.0f / Iz_f;
00252           Iz = Iz_f;
00253           Iz_f += dIzdx_f;
00254           const float z2 = 1.0f / Iz_f;
00255           ipx = InterpolStep;
00256           for (size_t f = 0; f < maxFloats; f++)
00257           {
00258             const float c = floats_f[f].Ic * z;
00259             floats[f].c = c;
00260             if (spans == 0)
00261             {
00262               floats_f[f].Ic += floats_f[f].dIcdxLast;
00263               floats[f].dcdx = (floats_f[f].Ic*z2 - c) * invLastSpan;
00264             }
00265             else
00266             {
00267               floats_f[f].Ic += floats_f[f].dIcdx;
00268               floats[f].dcdx = (floats_f[f].Ic*z2 - floats[f].c) >> InterpolShift;
00269             }
00270           }
00271         }
00272       }
00273       
00275       const ScanlineComp* GetFloat (size_t i) const { return &floats[i]; }
00276     };
00277 
00278     template<>
00279     struct InterpolateScanlinePersp<0> : public InterpolateScanlinePerspCommon
00280     {
00282       int InterpolStep;
00284       int InterpolShift;
00286       int ipx;
00288       int spans;
00289   
00291       void Setup (const InterpolateEdgePersp& L, const InterpolateEdgePersp& R,
00292         uint len, int ipolStep, int ipolShift)
00293       {
00294         InterpolStep = ipolStep;
00295         InterpolShift = ipolShift;
00296         spans = len / ipolStep;
00297   
00298         const float inv_l = 1.0f/len;
00299         const float ipf = (float)InterpolStep;
00300         ipx = InterpolStep;
00301         uint lastSpanSize = len % ipolStep;
00302         if (lastSpanSize == 0) lastSpanSize = ipolStep;
00303         Iz = Iz_f = L.Iz;
00304         dIzdx = dIzdx_f = (R.Iz - L.Iz) * inv_l;
00305         dIzdx_fLast = dIzdx_f * float (lastSpanSize);
00306         dIzdx_f *= ipf;
00307         Iz_f += dIzdx_f;
00308       }
00310       void Advance ()
00311       {
00312         if (--ipx > 0)
00313         {
00314           Iz += dIzdx;
00315         }
00316         else
00317         {
00318           if (--spans == 0)
00319           {
00320             dIzdx_f = dIzdx_fLast;
00321           }
00322           /* Note: Iz_f is "ahead" one interpolation span, ie when the
00323            * deltas are set up for the next, it has the value from the
00324            * beginning if that span. */
00325           Iz = Iz_f;
00326           Iz_f += dIzdx_f;
00327           ipx = InterpolStep;
00328         }
00329       }
00330       
00334       const ScanlineComp* GetFloat (size_t /*i*/) const { return 0; }
00335     };
00336     
00337     struct Pixel
00338     {
00339       struct tag_c
00340       {
00341         uint8 r;
00342         uint8 g;
00343         uint8 b;
00344         uint8 a;
00345       };
00346       union
00347       {
00348         tag_c c;
00349         uint32 ui32;
00350       };
00351       
00352       Pixel () {}
00353       Pixel (uint8 r, uint8 g, uint8 b, uint8 a)
00354       {
00355         c.r = r; c.g = g; c.b = b; c.a = a;
00356       }
00357       Pixel (uint32 ui) : ui32 (ui) { }
00358       
00359       CS_FORCEINLINE
00360       Pixel operator+ (const Pixel other)
00361       {
00362         // Poor man's SIMD... add two components at once.
00363         const uint32 rb1 = (ui32 & 0xff00ff00) >> 8;
00364         const uint32 ga1 = (ui32 & 0x00ff00ff);
00365         const uint32 rb2 = (other.ui32 & 0xff00ff00) >> 8;
00366         const uint32 ga2 = (other.ui32 & 0x00ff00ff);
00367         uint32 rb = rb1 + rb2;
00368         // Clamp
00369         if (rb & 0xff000000) { rb &= 0x0000ffff; rb |= 0x00ff0000; }
00370         if (rb & 0x0000ff00) { rb &= 0xffff0000; rb |= 0x000000ff; }
00371         uint32 ga = ga1 + ga2;
00372         if (ga & 0xff000000) { ga &= 0x0000ffff; ga |= 0x00ff0000; }
00373         if (ga & 0x0000ff00) { ga &= 0xffff0000; ga |= 0x000000ff; }
00374         return Pixel ((rb << 8) | ga);
00375       }
00376       CS_FORCEINLINE
00377       Pixel& operator += (const Pixel other)
00378       {
00379         return (*this = *this + other);
00380       }
00381       CS_FORCEINLINE
00382       Pixel operator~ () const
00383       {
00384         return Pixel (~ui32);
00385       }
00386       CS_FORCEINLINE
00387       friend Pixel operator* (const Pixel p1, const Pixel p2)
00388       {
00389         uint8 nr = (p1.c.r*(p2.c.r+1)) >> 8;
00390         uint8 ng = (p1.c.g*(p2.c.g+1)) >> 8;
00391         uint8 nb = (p1.c.b*(p2.c.b+1)) >> 8;
00392         uint8 na = (p1.c.a*(p2.c.a+1)) >> 8;
00393         return Pixel (nr, ng, nb, na);
00394       }
00395       CS_FORCEINLINE
00396       friend Pixel operator* (const Pixel p, const uint8 x)
00397       {
00398         // Poor man's SIMD...
00399         const uint v = x+1;
00400         const uint32 rb = (p.ui32 & 0xff00ff00) >> 8;
00401         const uint32 ga = (p.ui32 & 0x00ff00ff);
00402         return Pixel (((rb*v) & 0xff00ff00) | (((ga*v) >> 8) & 0x00ff00ff));
00403       }
00404       CS_FORCEINLINE
00405       Pixel& operator *= (const uint8 x)
00406       {
00407         return (*this = *this * x);
00408       }
00409     };
00410   } // namespace SoftShader
00411 } // namespace PluginCommon
00412 } // namespace CS
00413 
00418 #define CS_SOFT3D_VA_BUFINDEX(x)                                        \
00419   (CS_VATTRIB_ ## x - (CS_VATTRIB_ ## x >=  CS_VATTRIB_GENERIC_FIRST ?  \
00420   CS_VATTRIB_GENERIC_FIRST : CS_VATTRIB_SPECIFIC_FIRST))
00421 
00425 #define CS_SOFT3D_BUFFERFLAG(x)                 (1 << CS_SOFT3D_VA_BUFINDEX(x))
00426 
00429 #endif // __CS_CSPLUGINCOMMON_SOFTSHADER_TYPES_H__

Generated for Crystal Space by doxygen 1.4.7