t3dlib8.cpp
资源名称:Source.rar [点击查看]
上传用户:husern
上传日期:2018-01-20
资源大小:42486k
文件大小:215k
源码类别:
游戏
开发平台:
Visual C++
- bi = ((lights[curr_light].c_ambient.b * b_base) / 256);
- // ambient light has the same affect on each vertex
- r_sum0+=ri;
- g_sum0+=gi;
- b_sum0+=bi;
- r_sum1+=ri;
- g_sum1+=gi;
- b_sum1+=bi;
- r_sum2+=ri;
- g_sum2+=gi;
- b_sum2+=bi;
- // there better only be one ambient light!
- //Write_Error("nexiting ambient ,sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) /////////////////////////////////
- {
- //Write_Error("nentering infinite light...");
- // infinite lighting, we need the surface normal, and the direction
- // of the light source
- // no longer need to compute normal or length, we already have the vertex normal
- // and it's length is 1.0
- // ....
- // ok, recalling the lighting model for infinite lights
- // I(d)dir = I0dir * Cldir
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // need to perform lighting for each vertex (lots of redundant math, optimize later!)
- //Write_Error("nv0=[%f, %f, %f]=%f, v1=[%f, %f, %f]=%f, v2=[%f, %f, %f]=%f",
- // curr_poly->tvlist[0].n.x, curr_poly->tvlist[0].n.y,curr_poly->tvlist[0].n.z, VECTOR4D_Length(&curr_poly->tvlist[0].n),
- // curr_poly->tvlist[1].n.x, curr_poly->tvlist[1].n.y,curr_poly->tvlist[1].n.z, VECTOR4D_Length(&curr_poly->tvlist[1].n),
- // curr_poly->tvlist[2].n.x, curr_poly->tvlist[2].n.y,curr_poly->tvlist[2].n.z, VECTOR4D_Length(&curr_poly->tvlist[2].n) );
- // vertex 0
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_0].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp;
- r_sum0+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_1].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp;
- r_sum1+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 2
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_2].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp;
- r_sum2+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("nexiting infinite, color sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if infinite light
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) //////////////////////////////////////
- {
- // perform point light computations
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- // .. normal already in vertex
- //Write_Error("nEntering point light....");
- // compute vector from surface to light
- VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // perform the calculation for all 3 vertices
- // vertex 0
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_0].n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (dist * atten );
- r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_1].n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (dist * atten );
- r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 2
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_2].n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (dist * atten );
- r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("nexiting point light, rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if point
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ///////////////////////////////////////
- {
- // perform spotlight/point computations simplified model that uses
- // point light WITH a direction to simulate a spotlight
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- //Write_Error("nentering spotlight1....");
- // .. normal is already computed
- // compute vector from surface to light
- VECTOR4D_Build(&obj->vlist_trans[ vindex_0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // note that I use the direction of the light here rather than a the vector to the light
- // thus we are taking orientation into account which is similar to the spotlight model
- // vertex 0
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_0].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / ( atten );
- r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_1].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / ( atten );
- r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end i
- // vertex 2
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_2].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / ( atten );
- r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end i
- //Write_Error("nexiting spotlight1, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if spotlight1
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version //////////////////////////
- {
- // perform spot light computations
- // light model for spot light simple version is once again:
- // I0spotlight * Clspotlight * MAX( (l . s), 0)^pf
- // I(d)spotlight = __________________________________________
- // kc + kl*d + kq*d2
- // Where d = |p - s|, and pf = power factor
- // thus it's almost identical to the point, but has the extra term in the numerator
- // relating the angle between the light source and the point on the surface
- // .. already have normals and length are 1.0
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- //Write_Error("nEntering spotlight2...");
- // tons of redundant math here! lots to optimize later!
- // vertex 0
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_0].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &obj->vlist_trans[ vindex_0].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / ( atten );
- r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_1].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &obj->vlist_trans[ vindex_1].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / ( atten );
- r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- // vertex 2
- dp = VECTOR4D_Dot(&obj->vlist_trans[ vindex_2].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &obj->vlist_trans[ vindex_2].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / ( atten );
- r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- //Write_Error("nexiting spotlight2, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if spot light
- } // end for light
- // make sure colors aren't out of range
- if (r_sum0 > 255) r_sum0 = 255;
- if (g_sum0 > 255) g_sum0 = 255;
- if (b_sum0 > 255) b_sum0 = 255;
- if (r_sum1 > 255) r_sum1 = 255;
- if (g_sum1 > 255) g_sum1 = 255;
- if (b_sum1 > 255) b_sum1 = 255;
- if (r_sum2 > 255) r_sum2 = 255;
- if (g_sum2 > 255) g_sum2 = 255;
- if (b_sum2 > 255) b_sum2 = 255;
- //Write_Error("nwriting color for poly %d", poly);
- //Write_Error("n******** final sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- // write the colors, leave in 5.6.5 format, so we have more color range
- // since the rasterizer will scale down to 8-bit
- curr_poly->lit_color[0] = RGB16Bit(r_sum0, g_sum0, b_sum0);
- curr_poly->lit_color[1] = RGB16Bit(r_sum1, g_sum1, b_sum1);
- curr_poly->lit_color[2] = RGB16Bit(r_sum2, g_sum2, b_sum2);
- } // end if
- else // assume POLY4DV2_ATTR_SHADE_MODE_CONSTANT
- {
- // emmisive shading only, do nothing
- // ...
- curr_poly->lit_color[0] = curr_poly->color;
- //Write_Error("nentering constant shader, and exiting...");
- } // end if
- } // end for poly
- // return success
- return(1);
- } // end Light_OBJECT4DV2_World2
- //////////////////////////////////////////////////////////////////////////////
- int Light_RENDERLIST4DV2_World2_16(RENDERLIST4DV2_PTR rend_list, // list to process
- CAM4DV1_PTR cam, // camera position
- LIGHTV2_PTR lights, // light list (might have more than one)
- int max_lights) // maximum lights in list
- {
- // 16-bit version of function
- // function lights the entire rendering list based on the sent lights and camera. the function supports
- // constant/pure shading (emmisive), flat shading with ambient, infinite, point lights, and spot lights
- // note that this lighting function is rather brute force and simply follows the math, however
- // there are some clever integer operations that are used in scale 256 rather than going to floating
- // point, but why? floating point and ints are the same speed, HOWEVER, the conversion to and from floating
- // point can be cycle intensive, so if you can keep your calcs in ints then you can gain some speed
- // also note, type 1 spot lights are simply point lights with direction, the "cone" is more of a function
- // of the falloff due to attenuation, but they still look like spot lights
- // type 2 spot lights are implemented with the intensity having a dot product relationship with the
- // angle from the surface point to the light direction just like in the optimized model, but the pf term
- // that is used for a concentration control must be 1,2,3,.... integral and non-fractional
- // this function now performs emissive, flat, and gouraud lighting, results are stored in the
- // lit_color[] array of each polygon
- unsigned int r_base, g_base, b_base, // base color being lit
- r_sum, g_sum, b_sum, // sum of lighting process over all lights
- r_sum0, g_sum0, b_sum0,
- r_sum1, g_sum1, b_sum1,
- r_sum2, g_sum2, b_sum2,
- ri,gi,bi,
- shaded_color; // final color
- float dp, // dot product
- dist, // distance from light to surface
- dists,
- i, // general intensities
- nl, // length of normal
- atten; // attenuation computations
- VECTOR4D u, v, n, l, d, s; // used for cross product and light vector calculations
- //Write_Error("nEntering lighting function");
- // for each valid poly, light it...
- for (int poly=0; poly < rend_list->num_polys; poly++)
- {
- // acquire polygon
- POLYF4DV2_PTR curr_poly = rend_list->poly_ptrs[poly];
- // light this polygon if and only if it's not clipped, not culled,
- // active, and visible
- if (!(curr_poly->state & POLY4DV2_STATE_ACTIVE) ||
- (curr_poly->state & POLY4DV2_STATE_CLIPPED ) ||
- (curr_poly->state & POLY4DV2_STATE_BACKFACE) ||
- (curr_poly->state & POLY4DV2_STATE_LIT) )
- continue; // move onto next poly
- //Write_Error("npoly %d",poly);
- #ifdef DEBUG_ON
- // track rendering stats
- debug_polys_lit_per_frame++;
- #endif
- // set state of polygon to lit
- SET_BIT(curr_poly->state, POLY4DV2_STATE_LIT);
- // we will use the transformed polygon vertex list since the backface removal
- // only makes sense at the world coord stage further of the pipeline
- // test the lighting mode of the polygon (use flat for flat, gouraud))
- if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT)
- {
- //Write_Error("nEntering Flat Shader");
- // step 1: extract the base color out in RGB mode
- // assume 565 format
- _RGB565FROM16BIT(curr_poly->color, &r_base, &g_base, &b_base);
- // scale to 8 bit
- r_base <<= 3;
- g_base <<= 2;
- b_base <<= 3;
- //Write_Error("nBase color=%d,%d,%d", r_base, g_base, b_base);
- // initialize color sum
- r_sum = 0;
- g_sum = 0;
- b_sum = 0;
- //Write_Error("nsum color=%d,%d,%d", r_sum, g_sum, b_sum);
- // new optimization:
- // when there are multiple lights in the system we will end up performing numerous
- // redundant calculations to minimize this my strategy is to set key variables to
- // to MAX values on each loop, then during the lighting calcs to test the vars for
- // the max value, if they are the max value then the first light that needs the math
- // will do it, and then save the information into the variable (causing it to change state
- // from an invalid number) then any other lights that need the math can use the previously
- // computed value
- // set surface normal.z to FLT_MAX to flag it as non-computed
- n.z = FLT_MAX;
- // loop thru lights
- for (int curr_light = 0; curr_light < max_lights; curr_light++)
- {
- // is this light active
- if (lights[curr_light].state==LIGHTV2_STATE_OFF)
- continue;
- //Write_Error("nprocessing light %d",curr_light);
- // what kind of light are we dealing with
- if (lights[curr_light].attr & LIGHTV2_ATTR_AMBIENT)
- {
- //Write_Error("nEntering ambient light...");
- // simply multiply each channel against the color of the
- // polygon then divide by 256 to scale back to 0..255
- // use a shift in real life!!! >> 8
- r_sum+= ((lights[curr_light].c_ambient.r * r_base) / 256);
- g_sum+= ((lights[curr_light].c_ambient.g * g_base) / 256);
- b_sum+= ((lights[curr_light].c_ambient.b * b_base) / 256);
- //Write_Error("nambient sum=%d,%d,%d", r_sum, g_sum, b_sum);
- // there better only be one ambient light!
- } // end if
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) ///////////////////////////////////////////
- {
- //Write_Error("nEntering infinite light...");
- // infinite lighting, we need the surface normal, and the direction
- // of the light source
- // test if we already computed poly normal in previous calculation
- if (n.z==FLT_MAX)
- {
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- // build u, v
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- } // end if
- // at this point, we are almost ready, but we have to normalize the normal vector!
- // this is a key optimization we can make later, we can pre-compute the length of all polygon
- // normals, so this step can be optimized
- // compute length of normal
- //nl = VECTOR4D_Length_Fast2(&n);
- nl = curr_poly->nlength;
- // ok, recalling the lighting model for infinite lights
- // I(d)dir = I0dir * Cldir
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp/nl;
- r_sum+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("ninfinite sum=%d,%d,%d", r_sum, g_sum, b_sum);
- } // end if infinite light
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) ///////////////////////////////////////
- {
- //Write_Error("nEntering point light...");
- // perform point light computations
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- // test if we already computed poly normal in previous calculation
- if (n.z==FLT_MAX)
- {
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- // build u, v
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- } // end if
- // at this point, we are almost ready, but we have to normalize the normal vector!
- // this is a key optimization we can make later, we can pre-compute the length of all polygon
- // normals, so this step can be optimized
- // compute length of normal
- //nl = VECTOR4D_Length_Fast2(&n);
- nl = curr_poly->nlength;
- // compute vector from surface to light
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- dp = VECTOR4D_Dot(&n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (nl * dist * atten );
- r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("npoint sum=%d,%d,%d",r_sum,g_sum,b_sum);
- } // end if point
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ////////////////////////////////////
- {
- //Write_Error("nentering spot light1...");
- // perform spotlight/point computations simplified model that uses
- // point light WITH a direction to simulate a spotlight
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- // test if we already computed poly normal in previous calculation
- if (n.z==FLT_MAX)
- {
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- // build u, v
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- } // end if
- // at this point, we are almost ready, but we have to normalize the normal vector!
- // this is a key optimization we can make later, we can pre-compute the length of all polygon
- // normals, so this step can be optimized
- // compute length of normal
- //nl = VECTOR4D_Length_Fast2(&n);
- nl = curr_poly->nlength;
- // compute vector from surface to light
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // note that I use the direction of the light here rather than a the vector to the light
- // thus we are taking orientation into account which is similar to the spotlight model
- dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (nl * atten );
- r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("nspotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
- } // end if spotlight1
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version ////////////////////
- {
- //Write_Error("nEntering spotlight2 ...");
- // perform spot light computations
- // light model for spot light simple version is once again:
- // I0spotlight * Clspotlight * MAX( (l . s), 0)^pf
- // I(d)spotlight = __________________________________________
- // kc + kl*d + kq*d2
- // Where d = |p - s|, and pf = power factor
- // thus it's almost identical to the point, but has the extra term in the numerator
- // relating the angle between the light source and the point on the surface
- // test if we already computed poly normal in previous calculation
- if (n.z==FLT_MAX)
- {
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- // build u, v
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- } // end if
- // at this point, we are almost ready, but we have to normalize the normal vector!
- // this is a key optimization we can make later, we can pre-compute the length of all polygon
- // normals, so this step can be optimized
- // compute length of normal
- //nl = VECTOR4D_Length_Fast2(&n);
- nl = curr_poly->nlength;
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[0].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / (nl * atten );
- r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- //Write_Error("nSpotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
- } // end if spot light
- } // end for light
- // make sure colors aren't out of range
- if (r_sum > 255) r_sum = 255;
- if (g_sum > 255) g_sum = 255;
- if (b_sum > 255) b_sum = 255;
- //Write_Error("nWriting final values to polygon %d = %d,%d,%d", poly, r_sum, g_sum, b_sum);
- // write the color over current color
- curr_poly->lit_color[0] = RGB16Bit(r_sum, g_sum, b_sum);
- } // end if
- else
- if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD) /////////////////////////////////
- {
- // gouraud shade, unfortunetly at this point in the pipeline, we have lost the original
- // mesh, and only have triangles, thus, many triangles will share the same vertices and
- // they will get lit 2x since we don't have any way to tell this, alas, performing lighting
- // at the object level is a better idea when gouraud shading is performed since the
- // commonality of vertices is still intact, in any case, lighting here is similar to polygon
- // flat shaded, but we do it 3 times, once for each vertex, additionally there are lots
- // of opportunities for optimization, but I am going to lay off them for now, so the code
- // is intelligible, later we will optimize
- //Write_Error("nEntering gouraud shader...");
- // step 1: extract the base color out in RGB mode
- // assume 565 format
- _RGB565FROM16BIT(curr_poly->color, &r_base, &g_base, &b_base);
- // scale to 8 bit
- r_base <<= 3;
- g_base <<= 2;
- b_base <<= 3;
- //Write_Error("nBase color=%d, %d, %d", r_base, g_base, b_base);
- // initialize color sum(s) for vertices
- r_sum0 = 0;
- g_sum0 = 0;
- b_sum0 = 0;
- r_sum1 = 0;
- g_sum1 = 0;
- b_sum1 = 0;
- r_sum2 = 0;
- g_sum2 = 0;
- b_sum2 = 0;
- //Write_Error("nColor sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- // new optimization:
- // when there are multiple lights in the system we will end up performing numerous
- // redundant calculations to minimize this my strategy is to set key variables to
- // to MAX values on each loop, then during the lighting calcs to test the vars for
- // the max value, if they are the max value then the first light that needs the math
- // will do it, and then save the information into the variable (causing it to change state
- // from an invalid number) then any other lights that need the math can use the previously
- // computed value, however, since we already have the normals, not much here to cache on
- // a large scale, but small scale stuff is there, however, we will optimize those later
- // loop thru lights
- for (int curr_light = 0; curr_light < max_lights; curr_light++)
- {
- // is this light active
- if (lights[curr_light].state==LIGHTV2_STATE_OFF)
- continue;
- //Write_Error("nprocessing light %d", curr_light);
- // what kind of light are we dealing with
- if (lights[curr_light].attr & LIGHTV2_ATTR_AMBIENT) ///////////////////////////////
- {
- //Write_Error("nEntering ambient light....");
- // simply multiply each channel against the color of the
- // polygon then divide by 256 to scale back to 0..255
- // use a shift in real life!!! >> 8
- ri = ((lights[curr_light].c_ambient.r * r_base) / 256);
- gi = ((lights[curr_light].c_ambient.g * g_base) / 256);
- bi = ((lights[curr_light].c_ambient.b * b_base) / 256);
- // ambient light has the same affect on each vertex
- r_sum0+=ri;
- g_sum0+=gi;
- b_sum0+=bi;
- r_sum1+=ri;
- g_sum1+=gi;
- b_sum1+=bi;
- r_sum2+=ri;
- g_sum2+=gi;
- b_sum2+=bi;
- // there better only be one ambient light!
- //Write_Error("nexiting ambient ,sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) /////////////////////////////////
- {
- //Write_Error("nentering infinite light...");
- // infinite lighting, we need the surface normal, and the direction
- // of the light source
- // no longer need to compute normal or length, we already have the vertex normal
- // and it's length is 1.0
- // ....
- // ok, recalling the lighting model for infinite lights
- // I(d)dir = I0dir * Cldir
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // need to perform lighting for each vertex (lots of redundant math, optimize later!)
- //Write_Error("nv0=[%f, %f, %f]=%f, v1=[%f, %f, %f]=%f, v2=[%f, %f, %f]=%f",
- // curr_poly->tvlist[0].n.x, curr_poly->tvlist[0].n.y,curr_poly->tvlist[0].n.z, VECTOR4D_Length(&curr_poly->tvlist[0].n),
- // curr_poly->tvlist[1].n.x, curr_poly->tvlist[1].n.y,curr_poly->tvlist[1].n.z, VECTOR4D_Length(&curr_poly->tvlist[1].n),
- // curr_poly->tvlist[2].n.x, curr_poly->tvlist[2].n.y,curr_poly->tvlist[2].n.z, VECTOR4D_Length(&curr_poly->tvlist[2].n) );
- // vertex 0
- dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp;
- r_sum0+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp;
- r_sum1+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 2
- dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp;
- r_sum2+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("nexiting infinite, color sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if infinite light
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) //////////////////////////////////////
- {
- // perform point light computations
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- // .. normal already in vertex
- //Write_Error("nEntering point light....");
- // compute vector from surface to light
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // perform the calculation for all 3 vertices
- // vertex 0
- dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (dist * atten );
- r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (dist * atten );
- r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 2
- dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (dist * atten );
- r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("nexiting point light, rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if point
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ///////////////////////////////////////
- {
- // perform spotlight/point computations simplified model that uses
- // point light WITH a direction to simulate a spotlight
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- //Write_Error("nentering spotlight1....");
- // .. normal is already computed
- // compute vector from surface to light
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // note that I use the direction of the light here rather than a the vector to the light
- // thus we are taking orientation into account which is similar to the spotlight model
- // vertex 0
- dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / ( atten );
- r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / ( atten );
- r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end i
- // vertex 2
- dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / ( atten );
- r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end i
- //Write_Error("nexiting spotlight1, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if spotlight1
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version //////////////////////////
- {
- // perform spot light computations
- // light model for spot light simple version is once again:
- // I0spotlight * Clspotlight * MAX( (l . s), 0)^pf
- // I(d)spotlight = __________________________________________
- // kc + kl*d + kq*d2
- // Where d = |p - s|, and pf = power factor
- // thus it's almost identical to the point, but has the extra term in the numerator
- // relating the angle between the light source and the point on the surface
- // .. already have normals and length are 1.0
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- //Write_Error("nEntering spotlight2...");
- // tons of redundant math here! lots to optimize later!
- // vertex 0
- dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[0].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / ( atten );
- r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[1].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / ( atten );
- r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- // vertex 2
- dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[2].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / ( atten );
- r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- //Write_Error("nexiting spotlight2, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if spot light
- } // end for light
- // make sure colors aren't out of range
- if (r_sum0 > 255) r_sum0 = 255;
- if (g_sum0 > 255) g_sum0 = 255;
- if (b_sum0 > 255) b_sum0 = 255;
- if (r_sum1 > 255) r_sum1 = 255;
- if (g_sum1 > 255) g_sum1 = 255;
- if (b_sum1 > 255) b_sum1 = 255;
- if (r_sum2 > 255) r_sum2 = 255;
- if (g_sum2 > 255) g_sum2 = 255;
- if (b_sum2 > 255) b_sum2 = 255;
- //Write_Error("nwriting color for poly %d", poly);
- //Write_Error("n******** final sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- // write the colors
- curr_poly->lit_color[0] = RGB16Bit(r_sum0, g_sum0, b_sum0);
- curr_poly->lit_color[1] = RGB16Bit(r_sum1, g_sum1, b_sum1);
- curr_poly->lit_color[2] = RGB16Bit(r_sum2, g_sum2, b_sum2);
- } // end if
- else // assume POLY4DV2_ATTR_SHADE_MODE_CONSTANT
- {
- // emmisive shading only, do nothing
- // ...
- curr_poly->lit_color[0] = curr_poly->color;
- //Write_Error("nentering constant shader, and exiting...");
- } // end if
- } // end for poly
- // return success
- return(1);
- } // end Light_RENDERLIST4DV2_World2_16
- //////////////////////////////////////////////////////////////////////////////
- int Light_RENDERLIST4DV2_World2(RENDERLIST4DV2_PTR rend_list, // list to process
- CAM4DV1_PTR cam, // camera position
- LIGHTV2_PTR lights, // light list (might have more than one)
- int max_lights) // maximum lights in list
- {
- // {andre work in progress }
- // 8-bit version of function
- // function lights the entire rendering list based on the sent lights and camera. the function supports
- // constant/pure shading (emmisive), flat shading with ambient, infinite, point lights, and spot lights
- // note that this lighting function is rather brute force and simply follows the math, however
- // there are some clever integer operations that are used in scale 256 rather than going to floating
- // point, but why? floating point and ints are the same speed, HOWEVER, the conversion to and from floating
- // point can be cycle intensive, so if you can keep your calcs in ints then you can gain some speed
- // also note, type 1 spot lights are simply point lights with direction, the "cone" is more of a function
- // of the falloff due to attenuation, but they still look like spot lights
- // type 2 spot lights are implemented with the intensity having a dot product relationship with the
- // angle from the surface point to the light direction just like in the optimized model, but the pf term
- // that is used for a concentration control must be 1,2,3,.... integral and non-fractional
- // also note since we are dealing with a rendering list and not object, the final lit color is
- // immediately written over the real color
- unsigned int r_base, g_base, b_base, // base color being lit
- r_sum, g_sum, b_sum, // sum of lighting process over all lights
- r_sum0, g_sum0, b_sum0,
- r_sum1, g_sum1, b_sum1,
- r_sum2, g_sum2, b_sum2,
- ri,gi,bi,
- shaded_color; // final color
- float dp, // dot product
- dist, // distance from light to surface
- dists,
- i, // general intensities
- nl, // length of normal
- atten; // attenuation computations
- VECTOR4D u, v, n, l, d, s; // used for cross product and light vector calculations
- //Write_Error("nEntering lighting function");
- // for each valid poly, light it...
- for (int poly=0; poly < rend_list->num_polys; poly++)
- {
- // acquire polygon
- POLYF4DV2_PTR curr_poly = rend_list->poly_ptrs[poly];
- // light this polygon if and only if it's not clipped, not culled,
- // active, and visible
- if (!(curr_poly->state & POLY4DV2_STATE_ACTIVE) ||
- (curr_poly->state & POLY4DV2_STATE_CLIPPED ) ||
- (curr_poly->state & POLY4DV2_STATE_BACKFACE) ||
- (curr_poly->state & POLY4DV2_STATE_LIT) )
- continue; // move onto next poly
- //Write_Error("npoly %d",poly);
- #ifdef DEBUG_ON
- // track rendering stats
- debug_polys_lit_per_frame++;
- #endif
- // set state of polygon to lit
- SET_BIT(curr_poly->state, POLY4DV2_STATE_LIT);
- // we will use the transformed polygon vertex list since the backface removal
- // only makes sense at the world coord stage further of the pipeline
- // test the lighting mode of the polygon (use flat for flat, gouraud))
- if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_FLAT)
- {
- //Write_Error("nEntering Flat Shader");
- r_base = palette[curr_poly->color].peRed;
- g_base = palette[curr_poly->color].peGreen;
- b_base = palette[curr_poly->color].peBlue;
- //Write_Error("nBase color=%d,%d,%d", r_base, g_base, b_base);
- // initialize color sum
- r_sum = 0;
- g_sum = 0;
- b_sum = 0;
- //Write_Error("nsum color=%d,%d,%d", r_sum, g_sum, b_sum);
- // new optimization:
- // when there are multiple lights in the system we will end up performing numerous
- // redundant calculations to minimize this my strategy is to set key variables to
- // to MAX values on each loop, then during the lighting calcs to test the vars for
- // the max value, if they are the max value then the first light that needs the math
- // will do it, and then save the information into the variable (causing it to change state
- // from an invalid number) then any other lights that need the math can use the previously
- // computed value
- // set surface normal.z to FLT_MAX to flag it as non-computed
- n.z = FLT_MAX;
- // loop thru lights
- for (int curr_light = 0; curr_light < max_lights; curr_light++)
- {
- // is this light active
- if (lights[curr_light].state==LIGHTV2_STATE_OFF)
- continue;
- //Write_Error("nprocessing light %d",curr_light);
- // what kind of light are we dealing with
- if (lights[curr_light].attr & LIGHTV2_ATTR_AMBIENT)
- {
- //Write_Error("nEntering ambient light...");
- // simply multiply each channel against the color of the
- // polygon then divide by 256 to scale back to 0..255
- // use a shift in real life!!! >> 8
- r_sum+= ((lights[curr_light].c_ambient.r * r_base) / 256);
- g_sum+= ((lights[curr_light].c_ambient.g * g_base) / 256);
- b_sum+= ((lights[curr_light].c_ambient.b * b_base) / 256);
- //Write_Error("nambient sum=%d,%d,%d", r_sum, g_sum, b_sum);
- // there better only be one ambient light!
- } // end if
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) ///////////////////////////////////////////
- {
- //Write_Error("nEntering infinite light...");
- // infinite lighting, we need the surface normal, and the direction
- // of the light source
- // test if we already computed poly normal in previous calculation
- if (n.z==FLT_MAX)
- {
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- // build u, v
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- } // end if
- // at this point, we are almost ready, but we have to normalize the normal vector!
- // this is a key optimization we can make later, we can pre-compute the length of all polygon
- // normals, so this step can be optimized
- // compute length of normal
- //nl = VECTOR4D_Length_Fast2(&n);
- nl = curr_poly->nlength;
- // ok, recalling the lighting model for infinite lights
- // I(d)dir = I0dir * Cldir
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp/nl;
- r_sum+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("ninfinite sum=%d,%d,%d", r_sum, g_sum, b_sum);
- } // end if infinite light
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) ///////////////////////////////////////
- {
- //Write_Error("nEntering point light...");
- // perform point light computations
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- // test if we already computed poly normal in previous calculation
- if (n.z==FLT_MAX)
- {
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- // build u, v
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- } // end if
- // at this point, we are almost ready, but we have to normalize the normal vector!
- // this is a key optimization we can make later, we can pre-compute the length of all polygon
- // normals, so this step can be optimized
- // compute length of normal
- //nl = VECTOR4D_Length_Fast2(&n);
- nl = curr_poly->nlength;
- // compute vector from surface to light
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- dp = VECTOR4D_Dot(&n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (nl * dist * atten );
- r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("npoint sum=%d,%d,%d",r_sum,g_sum,b_sum);
- } // end if point
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ////////////////////////////////////
- {
- //Write_Error("nentering spot light1...");
- // perform spotlight/point computations simplified model that uses
- // point light WITH a direction to simulate a spotlight
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- // test if we already computed poly normal in previous calculation
- if (n.z==FLT_MAX)
- {
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- // build u, v
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- } // end if
- // at this point, we are almost ready, but we have to normalize the normal vector!
- // this is a key optimization we can make later, we can pre-compute the length of all polygon
- // normals, so this step can be optimized
- // compute length of normal
- //nl = VECTOR4D_Length_Fast2(&n);
- nl = curr_poly->nlength;
- // compute vector from surface to light
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // note that I use the direction of the light here rather than a the vector to the light
- // thus we are taking orientation into account which is similar to the spotlight model
- dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (nl * atten );
- r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("nspotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
- } // end if spotlight1
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version ////////////////////
- {
- //Write_Error("nEntering spotlight2 ...");
- // perform spot light computations
- // light model for spot light simple version is once again:
- // I0spotlight * Clspotlight * MAX( (l . s), 0)^pf
- // I(d)spotlight = __________________________________________
- // kc + kl*d + kq*d2
- // Where d = |p - s|, and pf = power factor
- // thus it's almost identical to the point, but has the extra term in the numerator
- // relating the angle between the light source and the point on the surface
- // test if we already computed poly normal in previous calculation
- if (n.z==FLT_MAX)
- {
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- // build u, v
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[1].v, &u);
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &curr_poly->tvlist[2].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- } // end if
- // at this point, we are almost ready, but we have to normalize the normal vector!
- // this is a key optimization we can make later, we can pre-compute the length of all polygon
- // normals, so this step can be optimized
- // compute length of normal
- //nl = VECTOR4D_Length_Fast2(&n);
- nl = curr_poly->nlength;
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- dp = VECTOR4D_Dot(&n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[0].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / (nl * atten );
- r_sum += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- //Write_Error("nSpotlight sum=%d,%d,%d",r_sum, g_sum, b_sum);
- } // end if spot light
- } // end for light
- // make sure colors aren't out of range
- if (r_sum > 255) r_sum = 255;
- if (g_sum > 255) g_sum = 255;
- if (b_sum > 255) b_sum = 255;
- //Write_Error("nWriting final values to polygon %d = %d,%d,%d", poly, r_sum, g_sum, b_sum);
- // write the color over current color
- curr_poly->lit_color[0] = rgblookup[RGB16Bit565(r_sum, g_sum, b_sum)];
- } // end if
- else
- if (curr_poly->attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD) /////////////////////////////////
- {
- // gouraud shade, unfortunetly at this point in the pipeline, we have lost the original
- // mesh, and only have triangles, thus, many triangles will share the same vertices and
- // they will get lit 2x since we don't have any way to tell this, alas, performing lighting
- // at the object level is a better idea when gouraud shading is performed since the
- // commonality of vertices is still intact, in any case, lighting here is similar to polygon
- // flat shaded, but we do it 3 times, once for each vertex, additionally there are lots
- // of opportunities for optimization, but I am going to lay off them for now, so the code
- // is intelligible, later we will optimize
- //Write_Error("nEntering gouraud shader...");
- // step 1: extract the base color out in RGB mode
- r_base = palette[curr_poly->color].peRed;
- g_base = palette[curr_poly->color].peGreen;
- b_base = palette[curr_poly->color].peBlue;
- //Write_Error("nBase color=%d, %d, %d", r_base, g_base, b_base);
- // initialize color sum(s) for vertices
- r_sum0 = 0;
- g_sum0 = 0;
- b_sum0 = 0;
- r_sum1 = 0;
- g_sum1 = 0;
- b_sum1 = 0;
- r_sum2 = 0;
- g_sum2 = 0;
- b_sum2 = 0;
- //Write_Error("nColor sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- // new optimization:
- // when there are multiple lights in the system we will end up performing numerous
- // redundant calculations to minimize this my strategy is to set key variables to
- // to MAX values on each loop, then during the lighting calcs to test the vars for
- // the max value, if they are the max value then the first light that needs the math
- // will do it, and then save the information into the variable (causing it to change state
- // from an invalid number) then any other lights that need the math can use the previously
- // computed value
- // loop thru lights
- for (int curr_light = 0; curr_light < max_lights; curr_light++)
- {
- // is this light active
- if (lights[curr_light].state==LIGHTV2_STATE_OFF)
- continue;
- //Write_Error("nprocessing light %d", curr_light);
- // what kind of light are we dealing with
- if (lights[curr_light].attr & LIGHTV2_ATTR_AMBIENT) ///////////////////////////////
- {
- //Write_Error("nEntering ambient light....");
- // simply multiply each channel against the color of the
- // polygon then divide by 256 to scale back to 0..255
- // use a shift in real life!!! >> 8
- ri = ((lights[curr_light].c_ambient.r * r_base) / 256);
- gi = ((lights[curr_light].c_ambient.g * g_base) / 256);
- bi = ((lights[curr_light].c_ambient.b * b_base) / 256);
- // ambient light has the same affect on each vertex
- r_sum0+=ri;
- g_sum0+=gi;
- b_sum0+=bi;
- r_sum1+=ri;
- g_sum1+=gi;
- b_sum1+=bi;
- r_sum2+=ri;
- g_sum2+=gi;
- b_sum2+=bi;
- // there better only be one ambient light!
- //Write_Error("nexiting ambient ,sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_INFINITE) /////////////////////////////////
- {
- //Write_Error("nentering infinite light...");
- // infinite lighting, we need the surface normal, and the direction
- // of the light source
- // no longer need to compute normal or length, we already have the vertex normal
- // and it's length is 1.0
- // ....
- // ok, recalling the lighting model for infinite lights
- // I(d)dir = I0dir * Cldir
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // need to perform lighting for each vertex (lots of redundant math, optimize later!)
- //Write_Error("nv0=[%f, %f, %f]=%f, v1=[%f, %f, %f]=%f, v2=[%f, %f, %f]=%f",
- // curr_poly->tvlist[0].n.x, curr_poly->tvlist[0].n.y,curr_poly->tvlist[0].n.z, VECTOR4D_Length(&curr_poly->tvlist[0].n),
- // curr_poly->tvlist[1].n.x, curr_poly->tvlist[1].n.y,curr_poly->tvlist[1].n.z, VECTOR4D_Length(&curr_poly->tvlist[1].n),
- // curr_poly->tvlist[2].n.x, curr_poly->tvlist[2].n.y,curr_poly->tvlist[2].n.z, VECTOR4D_Length(&curr_poly->tvlist[2].n) );
- // vertex 0
- dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp;
- r_sum0+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp;
- r_sum1+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 2
- dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- i = 128*dp;
- r_sum2+= (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2+= (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2+= (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("nexiting infinite, color sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if infinite light
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_POINT) //////////////////////////////////////
- {
- // perform point light computations
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- // .. normal already in vertex
- //Write_Error("nEntering point light....");
- // compute vector from surface to light
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // perform the calculation for all 3 vertices
- // vertex 0
- dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (dist * atten );
- r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (dist * atten );
- r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 2
- dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &l);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / (dist * atten );
- r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- //Write_Error("nexiting point light, rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if point
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT1) ///////////////////////////////////////
- {
- // perform spotlight/point computations simplified model that uses
- // point light WITH a direction to simulate a spotlight
- // light model for point light is once again:
- // I0point * Clpoint
- // I(d)point = ___________________
- // kc + kl*d + kq*d2
- //
- // Where d = |p - s|
- // thus it's almost identical to the infinite light, but attenuates as a function
- // of distance from the point source to the surface point being lit
- //Write_Error("nentering spotlight1....");
- // .. normal is already computed
- // compute vector from surface to light
- VECTOR4D_Build(&curr_poly->tvlist[0].v, &lights[curr_light].tpos, &l);
- // compute distance and attenuation
- dist = VECTOR4D_Length_Fast2(&l);
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- // note that I use the direction of the light here rather than a the vector to the light
- // thus we are taking orientation into account which is similar to the spotlight model
- // vertex 0
- dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / ( atten );
- r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / ( atten );
- r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end i
- // vertex 2
- dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- atten = (lights[curr_light].kc + lights[curr_light].kl*dist + lights[curr_light].kq*dist*dist);
- i = 128*dp / ( atten );
- r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end i
- //Write_Error("nexiting spotlight1, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if spotlight1
- else
- if (lights[curr_light].attr & LIGHTV2_ATTR_SPOTLIGHT2) // simple version //////////////////////////
- {
- // perform spot light computations
- // light model for spot light simple version is once again:
- // I0spotlight * Clspotlight * MAX( (l . s), 0)^pf
- // I(d)spotlight = __________________________________________
- // kc + kl*d + kq*d2
- // Where d = |p - s|, and pf = power factor
- // thus it's almost identical to the point, but has the extra term in the numerator
- // relating the angle between the light source and the point on the surface
- // .. already have normals and length are 1.0
- // and for the diffuse model
- // Itotald = Rsdiffuse*Idiffuse * (n . l)
- // so we basically need to multiple it all together
- // notice the scaling by 128, I want to avoid floating point calculations, not because they
- // are slower, but the conversion to and from cost cycles
- //Write_Error("nEntering spotlight2...");
- // tons of redundant math here! lots to optimize later!
- // vertex 0
- dp = VECTOR4D_Dot(&curr_poly->tvlist[0].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[0].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / ( atten );
- r_sum0 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum0 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum0 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- // vertex 1
- dp = VECTOR4D_Dot(&curr_poly->tvlist[1].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[1].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / ( atten );
- r_sum1 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum1 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum1 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- // vertex 2
- dp = VECTOR4D_Dot(&curr_poly->tvlist[2].n, &lights[curr_light].tdir);
- // only add light if dp > 0
- if (dp > 0)
- {
- // compute vector from light to surface (different from l which IS the light dir)
- VECTOR4D_Build( &lights[curr_light].tpos, &curr_poly->tvlist[2].v, &s);
- // compute length of s (distance to light source) to normalize s for lighting calc
- dists = VECTOR4D_Length_Fast2(&s);
- // compute spot light term (s . l)
- float dpsl = VECTOR4D_Dot(&s, &lights[curr_light].tdir)/dists;
- // proceed only if term is positive
- if (dpsl > 0)
- {
- // compute attenuation
- atten = (lights[curr_light].kc + lights[curr_light].kl*dists + lights[curr_light].kq*dists*dists);
- // for speed reasons, pf exponents that are less that 1.0 are out of the question, and exponents
- // must be integral
- float dpsl_exp = dpsl;
- // exponentiate for positive integral powers
- for (int e_index = 1; e_index < (int)lights[curr_light].pf; e_index++)
- dpsl_exp*=dpsl;
- // now dpsl_exp holds (dpsl)^pf power which is of course (s . l)^pf
- i = 128*dp * dpsl_exp / ( atten );
- r_sum2 += (lights[curr_light].c_diffuse.r * r_base * i) / (256*128);
- g_sum2 += (lights[curr_light].c_diffuse.g * g_base * i) / (256*128);
- b_sum2 += (lights[curr_light].c_diffuse.b * b_base * i) / (256*128);
- } // end if
- } // end if
- //Write_Error("nexiting spotlight2, sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- } // end if spot light
- } // end for light
- // make sure colors aren't out of range
- if (r_sum0 > 255) r_sum0 = 255;
- if (g_sum0 > 255) g_sum0 = 255;
- if (b_sum0 > 255) b_sum0 = 255;
- if (r_sum1 > 255) r_sum1 = 255;
- if (g_sum1 > 255) g_sum1 = 255;
- if (b_sum1 > 255) b_sum1 = 255;
- if (r_sum2 > 255) r_sum2 = 255;
- if (g_sum2 > 255) g_sum2 = 255;
- if (b_sum2 > 255) b_sum2 = 255;
- //Write_Error("nwriting color for poly %d", poly);
- //Write_Error("n******** final sums rgb0[%d, %d, %d], rgb1[%d,%d,%d], rgb2[%d,%d,%d]", r_sum0, g_sum0, b_sum0, r_sum1, g_sum1, b_sum1, r_sum2, g_sum2, b_sum2);
- // write all colors in RGB form since we need to interpolate at the rasterizer
- curr_poly->lit_color[0] = RGB16Bit(r_sum0, g_sum0, b_sum0);
- curr_poly->lit_color[1] = RGB16Bit(r_sum1, g_sum1, b_sum1);
- curr_poly->lit_color[2] = RGB16Bit(r_sum2, g_sum2, b_sum2);
- } // end if
- else // assume POLY4DV2_ATTR_SHADE_MODE_CONSTANT
- {
- // emmisive shading only, do nothing
- // ...
- curr_poly->lit_color[0] = curr_poly->color;
- //Write_Error("nentering constant shader, and exiting...");
- } // end if
- } // end for poly
- // return success
- return(1);
- } // end Light_RENDERLIST4DV2_World2
- //////////////////////////////////////////////////////////////////////////////////////
- void Transform_LIGHTSV2(LIGHTV2_PTR lights, // array of lights to transform
- int num_lights, // number of lights to transform
- MATRIX4X4_PTR mt, // transformation matrix
- int coord_select) // selects coords to transform
- {
- // this function simply transforms all of the lights by the transformation matrix
- // this function is used to place the lights in camera space for example, so that
- // lighting calculations are correct if the lighting function is called AFTER
- // the polygons have already been trasformed to camera coordinates
- // also, later we may decided to optimize this a little by determining
- // the light type and only rotating what is needed, however there are thousands
- // of vertices in a scene and not rotating 10 more points isn't going to make
- // a difference
- // NOTE: This function MUST be called even if a transform to the lights
- // is not desired, that is, you are lighting in world coords, in this case
- // the local light positions and orientations MUST still be copied into the
- // working variables for the lighting engine to use pos->tpos, dir->tdir
- // hence, call this function with TRANSFORM_COPY_LOCAL_TO_TRANS
- // with a matrix of NULL
- int curr_light; // current light in loop
- MATRIX4X4 mr; // used to build up rotation aspect of matrix only
- // we need to rotate the direction vectors of the lights also, but
- // the translation factors must be zeroed out in the matrix otherwise
- // the results will be incorrect, thus make a copy of the matrix and zero
- // the translation factors
- if (mt!=NULL)
- {
- MAT_COPY_4X4(mt, &mr);
- // zero translation factors
- mr.M30 = mr.M31 = mr.M32 = 0;
- } // end if
- // what coordinates should be transformed?
- switch(coord_select)
- {
- case TRANSFORM_COPY_LOCAL_TO_TRANS:
- {
- // loop thru all the lights
- for (curr_light = 0; curr_light < num_lights; curr_light++)
- {
- lights[curr_light].tpos = lights[curr_light].pos;
- lights[curr_light].tdir = lights[curr_light].dir;
- } // end for
- } break;
- case TRANSFORM_LOCAL_ONLY:
- {
- // loop thru all the lights
- for (curr_light = 0; curr_light < num_lights; curr_light++)
- {
- // transform the local/world light coordinates in place
- POINT4D presult; // hold result of each transformation
- // transform point position of each light
- Mat_Mul_VECTOR4D_4X4(&lights[curr_light].pos, mt, &presult);
- // store result back
- VECTOR4D_COPY(&lights[curr_light].pos, &presult);
- // transform direction vector
- Mat_Mul_VECTOR4D_4X4(&lights[curr_light].dir, &mr, &presult);
- // store result back
- VECTOR4D_COPY(&lights[curr_light].dir, &presult);
- } // end for
- } break;
- case TRANSFORM_TRANS_ONLY:
- {
- // loop thru all the lights
- for (curr_light = 0; curr_light < num_lights; curr_light++)
- {
- // transform each "transformed" light
- POINT4D presult; // hold result of each transformation
- // transform point position of each light
- Mat_Mul_VECTOR4D_4X4(&lights[curr_light].tpos, mt, &presult);
- // store result back
- VECTOR4D_COPY(&lights[curr_light].tpos, &presult);
- // transform direction vector
- Mat_Mul_VECTOR4D_4X4(&lights[curr_light].tdir, &mr, &presult);
- // store result back
- VECTOR4D_COPY(&lights[curr_light].tdir, &presult);
- } // end for
- } break;
- case TRANSFORM_LOCAL_TO_TRANS:
- {
- // loop thru all the lights
- for (curr_light = 0; curr_light < num_lights; curr_light++)
- {
- // transform each local/world light and place the results into the transformed
- // storage, this is the usual way the function will be called
- POINT4D presult; // hold result of each transformation
- // transform point position of each light
- Mat_Mul_VECTOR4D_4X4(&lights[curr_light].pos, mt, &lights[curr_light].tpos);
- // transform direction vector
- Mat_Mul_VECTOR4D_4X4(&lights[curr_light].dir, &mr, &lights[curr_light].tdir);
- } // end for
- } break;
- default: break;
- } // end switch
- } // end Transform_LIGHTSV2