void TerrainPatch::Illuminate(Color ambient, List<Light>& lights) { if (!model || model->NumVerts() < 1) return; Surface* s = model->GetSurfaces().first(); if (!s) return; illuminating = true; // clear the solid lights to ambient: VertexSet* vset = s->GetVertexSet(); int nverts = vset->nverts; DWORD aval = ambient.Value(); for (int i = 0; i < nverts; i++) { vset->diffuse[i] = aval; } TerrainRegion* trgn = terrain->GetRegion(); bool eclipsed = false; bool first = terrain->IsFirstPatch(this); if (trgn && !first) { eclipsed = trgn->IsEclipsed(); } // for sun and back lights: ListIter<Light> iter = lights; while (++iter) { Light* light = iter.value(); if (!light->IsDirectional()) // only do sun and continue; // back lights if (light->CastsShadow() && first) { eclipsed = light->Location().y < -100 || // has sun set, or scene->IsLightObscured(vset->loc[0], // is sun in eclipse light->Location(), // by orbital body radius); // such as a moon? } if (!light->CastsShadow() || !eclipsed) { Vec3 vl = light->Location(); vl.Normalize(); for (int i = 0; i < nverts; i++) { Vec3& nrm = vset->nrm[i]; double val = 0; double gain = vl * nrm; if (gain > 0) { val = light->Intensity() * (0.85 * gain); if (val > 1) val = 1; } if (val > 0.01) vset->diffuse[i] = ((light->GetColor().dim(val)) + vset->diffuse[i]).Value(); } } } // combine blend weights: if (ndetail >= 2) { for (int i = 0; i < nverts; i++) { vset->diffuse[i] = vset->specular[i] | (vset->diffuse[i] & 0x00ffffff); } } if (trgn && first) { trgn->SetEclipsed(eclipsed); } InvalidateSurfaceData(); illuminating = false; }