nuclear@0: #include nuclear@0: #include "3dscene.h" nuclear@0: nuclear@0: using std::string; nuclear@0: nuclear@0: Scene::Scene(GraphicsContext *gc) { nuclear@0: this->gc = gc; nuclear@0: nuclear@0: ActiveCamera = 0; nuclear@0: Shadows = false; nuclear@0: LightHalos = false; nuclear@0: HaloSize = 10.0f; nuclear@0: UseFog = false; nuclear@0: nuclear@0: memset(lights, 0, 8 * sizeof(Light*)); nuclear@0: nuclear@0: AmbientLight = Color(0.0f, 0.0f, 0.0f); nuclear@0: ManageData = true; nuclear@0: } nuclear@0: nuclear@0: Scene::~Scene() { nuclear@0: nuclear@0: if(ManageData) { nuclear@0: std::list::iterator obj = objects.begin(); nuclear@0: while(obj != objects.end()) { nuclear@0: delete *obj++; nuclear@0: } nuclear@0: nuclear@0: std::list::iterator cam = cameras.begin(); nuclear@0: while(cam != cameras.end()) { nuclear@0: delete *cam++; nuclear@0: } nuclear@0: nuclear@0: for(int i=0; i<8; i++) { nuclear@0: delete lights[i]; nuclear@0: } nuclear@0: nuclear@0: std::list::iterator citer = curves.begin(); nuclear@0: while(citer != curves.end()) { nuclear@0: delete *citer++; nuclear@0: } nuclear@0: nuclear@0: std::list::iterator sv = StaticShadowVolumes.begin(); nuclear@0: while(sv != StaticShadowVolumes.end()) { nuclear@0: delete (*sv++).shadow_mesh; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: } nuclear@0: nuclear@0: void Scene::SetGraphicsContext(GraphicsContext *gc) { nuclear@0: this->gc = gc; nuclear@0: } nuclear@0: nuclear@0: void Scene::AddCamera(Camera *cam) { nuclear@0: cameras.push_back(cam); nuclear@0: if(!ActiveCamera) ActiveCamera = cam; nuclear@0: } nuclear@0: nuclear@0: void Scene::AddLight(Light *light) { nuclear@0: for(int i=0; i<8; i++) { nuclear@0: if(!lights[i]) { nuclear@0: lights[i] = light; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Scene::AddObject(Object *obj) { nuclear@0: if(obj->material.Alpha < 1.0f) { nuclear@0: objects.push_back(obj); nuclear@0: } else { nuclear@0: objects.push_front(obj); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Scene::AddStaticShadowVolume(TriMesh *mesh, const Light *light) { nuclear@0: ShadowVolume svol; nuclear@0: svol.shadow_mesh = mesh; nuclear@0: svol.light = light; nuclear@0: StaticShadowVolumes.push_back(svol); nuclear@0: } nuclear@0: nuclear@0: void Scene::AddCurve(Curve *curve) { nuclear@0: curves.push_back(curve); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void Scene::RemoveObject(const Object *obj) { nuclear@0: std::list::iterator iter = objects.begin(); nuclear@0: while(iter != objects.end()) { nuclear@0: if(obj == *iter) { nuclear@0: objects.erase(iter); nuclear@0: return; nuclear@0: } nuclear@0: iter++; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Scene::RemoveLight(const Light *light) { nuclear@0: for(int i=0; i<8; i++) { nuclear@0: if(light = lights[i]) { nuclear@0: lights[i] = 0; nuclear@0: return; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: Camera *Scene::GetCamera(const char *name) { nuclear@0: std::list::iterator iter = cameras.begin(); nuclear@0: while(iter != cameras.end()) { nuclear@0: if(!strcmp((*iter)->name.c_str(), name)) return *iter; nuclear@0: iter++; nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: Light *Scene::GetLight(const char *name) { nuclear@0: for(int i=0; i<8; i++) { nuclear@0: if(!strcmp(lights[i]->name.c_str(), name)) return lights[i]; nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: Object *Scene::GetObject(const char *name) { nuclear@0: std::list::iterator iter = objects.begin(); nuclear@0: while(iter != objects.end()) { nuclear@0: if(!strcmp((*iter)->name.c_str(), name)) return *iter; nuclear@0: iter++; nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: Curve *Scene::GetCurve(const char *name) { nuclear@0: std::list::iterator iter = curves.begin(); nuclear@0: while(iter != curves.end()) { nuclear@0: if(!strcmp((*iter)->name.c_str(), name)) return *iter; nuclear@0: iter++; nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: std::list *Scene::GetObjectsList() { nuclear@0: return &objects; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void Scene::SetActiveCamera(Camera *cam) { nuclear@0: ActiveCamera = cam; nuclear@0: } nuclear@0: nuclear@0: Camera *Scene::GetActiveCamera() const { nuclear@0: return ActiveCamera; nuclear@0: } nuclear@0: nuclear@0: void Scene::SetShadows(bool enable) { nuclear@0: Shadows = enable; nuclear@0: } nuclear@0: nuclear@0: void Scene::SetHaloDrawing(bool enable) { nuclear@0: LightHalos = enable; nuclear@0: } nuclear@0: nuclear@0: void Scene::SetHaloSize(float size) { nuclear@0: HaloSize = size; nuclear@0: } nuclear@0: nuclear@0: void Scene::SetAmbientLight(Color ambient) { nuclear@0: AmbientLight = ambient; nuclear@0: } nuclear@0: nuclear@0: Color Scene::GetAmbientLight() const { nuclear@0: return AmbientLight; nuclear@0: } nuclear@0: nuclear@0: void Scene::SetFog(bool enable, Color FogColor, float Near, float Far) { nuclear@0: UseFog = enable; nuclear@0: if(enable) { nuclear@0: this->FogColor = FogColor; nuclear@0: NearFogRange = Near; nuclear@0: FarFogRange = Far; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void Scene::SetupLights() const { nuclear@0: int LightIndex = 0; nuclear@0: for(int i=0; i<8; i++) { nuclear@0: if(lights[i]) { nuclear@0: lights[i]->SetLight(LightIndex++, gc); nuclear@0: } nuclear@0: } nuclear@0: gc->D3DDevice->LightEnable(LightIndex, false); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void Scene::RenderShadows() const { nuclear@0: nuclear@0: for(int i=0, slight=0; i<8; i++) { nuclear@0: if(!lights[i] || !lights[i]->GetShadowCasting()) continue; nuclear@0: nuclear@0: // disable shadow casting light and render the scene (first pass) nuclear@0: gc->SetAlphaBlending(true); nuclear@0: gc->D3DDevice->LightEnable(i, false); nuclear@0: std::list::const_iterator iter = objects.begin(); nuclear@0: while(iter != objects.end()) { nuclear@0: Object *obj = *iter++; nuclear@0: obj->Render(); nuclear@0: } nuclear@0: gc->D3DDevice->LightEnable(i, true); nuclear@0: gc->SetAlphaBlending(false); nuclear@0: nuclear@0: // shadow volume front faces nuclear@0: gc->SetZWrite(false); nuclear@0: gc->SetColorWrite(false, false, false, false); nuclear@0: gc->SetLighting(false); nuclear@0: nuclear@0: gc->SetStencilBuffering(true); nuclear@0: gc->SetStencilFunc(CMP_ALWAYS); nuclear@0: gc->SetStencilOp(SOP_KEEP, SOP_KEEP, SOP_INC); nuclear@0: nuclear@0: iter = objects.begin(); nuclear@0: while(iter != objects.end()) { nuclear@0: Object *obj = *iter++; nuclear@0: TriMesh *mesh = obj->GetShadowVolume(slight); nuclear@0: if(mesh) { nuclear@0: gc->SetWorldMatrix(obj->GetWorldTransform()); nuclear@0: gc->Draw(const_cast(mesh->GetVertexArray()), mesh->GetVertexCount()); nuclear@0: nuclear@0: // back faces pass nuclear@0: //gc->SetFrontFace(CounterClockwise); nuclear@0: //gc->SetStencilOp(SOP_KEEP, SOP_KEEP, SOP_DEC); nuclear@0: nuclear@0: //gc->Draw(const_cast(mesh->GetVertexArray()), mesh->GetVertexCount()); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // static shadow volumes nuclear@0: gc->SetWorldMatrix(Matrix4x4()); nuclear@0: std::list::const_iterator shadow_iter = StaticShadowVolumes.begin(); nuclear@0: while(shadow_iter != StaticShadowVolumes.end()) { nuclear@0: if(shadow_iter->light == lights[i]) { nuclear@0: gc->Draw(const_cast(shadow_iter->shadow_mesh->GetVertexArray()), shadow_iter->shadow_mesh->GetVertexCount()); nuclear@0: } nuclear@0: shadow_iter++; nuclear@0: } nuclear@0: nuclear@0: // back faces pass nuclear@0: gc->SetFrontFace(CounterClockwise); nuclear@0: gc->SetStencilOp(SOP_KEEP, SOP_KEEP, SOP_DEC); nuclear@0: nuclear@0: iter = objects.begin(); nuclear@0: while(iter != objects.end()) { nuclear@0: Object *obj = *iter++; nuclear@0: TriMesh *mesh = obj->GetShadowVolume(slight); nuclear@0: if(mesh) { nuclear@0: gc->SetWorldMatrix(obj->GetWorldTransform()); nuclear@0: gc->Draw(const_cast(mesh->GetVertexArray()), mesh->GetVertexCount()); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // static shadow volumes nuclear@0: gc->SetWorldMatrix(Matrix4x4()); nuclear@0: shadow_iter = StaticShadowVolumes.begin(); nuclear@0: while(shadow_iter != StaticShadowVolumes.end()) { nuclear@0: if(shadow_iter->light == lights[i]) { nuclear@0: gc->Draw(const_cast(shadow_iter->shadow_mesh->GetVertexArray()), shadow_iter->shadow_mesh->GetVertexCount()); nuclear@0: } nuclear@0: shadow_iter++; nuclear@0: } nuclear@0: nuclear@0: gc->SetFrontFace(Clockwise); nuclear@0: nuclear@0: gc->SetLighting(true); nuclear@0: gc->SetZWrite(true); nuclear@0: gc->SetColorWrite(true, true, true, true); nuclear@0: nuclear@0: gc->SetStencilOp(SOP_KEEP, SOP_KEEP, SOP_KEEP); nuclear@0: gc->SetStencilFunc(CMP_EQUAL); nuclear@0: gc->SetStencilReference(0); nuclear@0: nuclear@0: gc->SetLighting(true); nuclear@0: //SetupLights(); nuclear@0: nuclear@0: slight++; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Scene::Render() const { nuclear@0: gc->SetAmbientLight(AmbientLight); nuclear@0: nuclear@0: // set camera nuclear@0: if(!ActiveCamera) return; nuclear@0: ActiveCamera->CreateCameraMatrix(); nuclear@0: gc->SetViewMatrix(ActiveCamera->GetCameraMatrix()); nuclear@0: nuclear@0: // set projection matrix nuclear@0: float NearClip, FarClip; nuclear@0: Matrix4x4 ProjMat; nuclear@0: ActiveCamera->GetClippingPlanes(&NearClip, &FarClip); nuclear@0: CreateProjectionMatrix(&ProjMat, ActiveCamera->GetFOV(), 1.3333333f, NearClip, FarClip); nuclear@0: gc->SetProjectionMatrix(ProjMat); nuclear@0: nuclear@0: SetupLights(); nuclear@0: nuclear@0: // render shadows nuclear@0: if(Shadows) { nuclear@0: nuclear@0: // make array of shadow-casting lights nuclear@0: Light *ShadowCasters[8]; nuclear@0: Light **lptr = ShadowCasters; nuclear@0: for(int i=0; i<8; i++) { nuclear@0: if(lights[i] && lights[i]->GetShadowCasting()) { nuclear@0: *lptr++ = lights[i]; nuclear@0: } nuclear@0: } nuclear@0: int ShadowCasterCount = (int)(lptr - ShadowCasters); nuclear@0: nuclear@0: std::list::const_iterator iter = objects.begin(); nuclear@0: while(iter != objects.end()) { nuclear@0: Object *obj = *iter++; nuclear@0: nuclear@0: if(obj->GetShadowCasting()) { nuclear@0: obj->CalculateShadows((const Light**)ShadowCasters, ShadowCasterCount); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: RenderShadows(); nuclear@0: } nuclear@0: nuclear@0: // render objects nuclear@0: std::list::const_iterator iter = objects.begin(); nuclear@0: while(iter != objects.end()) { nuclear@0: Object *obj = *iter++; nuclear@0: nuclear@0: obj->Render(); nuclear@0: } nuclear@0: nuclear@0: if(Shadows) { nuclear@0: gc->SetStencilBuffering(false); nuclear@0: gc->SetStencilFunc(CMP_ALWAYS); nuclear@0: } nuclear@0: nuclear@0: if(LightHalos) { nuclear@0: for(int i=0; i<8; i++) { nuclear@0: if(lights[i]) lights[i]->Draw(gc, HaloSize); nuclear@0: } nuclear@0: } nuclear@0: }