kick
|
00001 // 00002 // Scene.cpp 00003 // KickCPP 00004 // 00005 // Created by Morten Nobel-Jørgensen on 5/21/13. 00006 // Copyright (c) 2013 Morten Nobel-Joergensen. All rights reserved. 00007 // 00008 00009 #include "kick/scene/scene.h" 00010 #include <iostream> 00011 #include <algorithm> 00012 #include "rapidjson/rapidjson.h" 00013 #include "rapidjson/writer.h" 00014 #include "kick/scene/engine_uniforms.h" 00015 #include "kick/scene/camera.h" 00016 #include "updatable.h" 00017 #include "kick/scene/camera_orthographic.h" 00018 #include "kick/scene/camera_perspective.h" 00019 #include "kick/scene/mesh_renderer.h" 00020 #include "kick/mesh/mesh_factory.h" 00021 #include "kick/mesh/mesh.h" 00022 #include "kick/core/engine.h" 00023 #include "kick/scene/light.h" 00024 #include "kick/2d/sprite.h" 00025 #include "glm/gtx/string_cast.hpp" 00026 #include "kick/texture/texture_atlas.h" 00027 #include "kick/2d/button.h" 00028 #include "canvas.h" 00029 00030 using namespace std; 00031 00032 namespace kick { 00033 00034 Scene::Scene(const std::string & name) 00035 : mName(name) 00036 { 00037 } 00038 00039 Scene::~Scene(){ 00040 } 00041 00042 Scene::Scene(Scene&& scene) 00043 : mGameObjects(move(scene.mGameObjects)), 00044 mCameras(move(scene.mCameras)), 00045 mName(move(scene.mName)) 00046 {} 00047 00048 Scene& Scene::operator=(Scene&& other){ 00049 if (this != &other){ 00050 mGameObjects = move(other.mGameObjects); 00051 mCameras = move(other.mCameras); 00052 mName = move(other.mName); 00053 } 00054 return *this; 00055 } 00056 00057 GameObject *Scene::createGameObject(const string &name){ 00058 auto res = new GameObject(name, this, ++mUniqueIdGenerator); 00059 EventListener<std::pair<std::shared_ptr<Component>, ComponentUpdateStatus>> eventListener = res->componentEvent.createListener([&](std::pair<std::shared_ptr<Component>, ComponentUpdateStatus> e){ 00060 componentListener(e.first, e.second); 00061 }); 00062 00063 mGameObjects.push_back(unique_ptr<GameObject>(res)); 00064 mComponentListeners[res] = move(eventListener); 00065 return res; 00066 } 00067 00068 void Scene::destroyGameObject(GameObject *gameObject){ 00069 for (int i=0;i< mGameObjects.size();i++){ 00070 if (mGameObjects[i].get() == gameObject){ 00071 mComponentListeners.erase(gameObject); 00072 mGameObjects.erase(mGameObjects.begin()+i); 00073 return; 00074 } 00075 } 00076 } 00077 00078 std::string Scene::name() const{ 00079 return mName; 00080 } 00081 00082 void Scene::setName(std::string name){ 00083 this->mName = name; 00084 } 00085 00086 GameObjectIter Scene::begin() const { 00087 return mGameObjects.begin(); 00088 } 00089 00090 GameObjectIter Scene::end() const { 00091 return mGameObjects.end(); 00092 } 00093 00094 void Scene::update() { 00095 for (auto & component : mUpdatable) { 00096 component->update(); 00097 } 00098 } 00099 00100 void Scene::render(EngineUniforms* engineUniforms){ 00101 engineUniforms->sceneLights = &mSceneLights; 00102 std::sort(mCameras.begin(), mCameras.end(), [](std::shared_ptr<Camera> c1, std::shared_ptr<Camera> c2){ 00103 return c1->index() < c2->index(); 00104 }); 00105 for (auto & camera : mCameras) { 00106 if (camera->enabled()){ 00107 engineUniforms->currentCamera = camera; 00108 camera->render(engineUniforms); 00109 } 00110 } 00111 } 00112 00113 void Scene::componentListener(std::shared_ptr<Component> component, ComponentUpdateStatus status){ 00114 componentEvents.notifyListeners({component, status}); 00115 auto camera = std::dynamic_pointer_cast<Camera>(component); 00116 auto light = std::dynamic_pointer_cast<Light>(component); 00117 if (status == ComponentUpdateStatus::Created){ 00118 if (camera){ 00119 mCameras.push_back(camera); 00120 } else if (light){ 00121 mLights[light] = light->lightTypeChanged.createListener([&](std::shared_ptr<Light> l){ 00122 rebuildSceneLights(); 00123 }, 0); 00124 addLight(light); 00125 } 00126 auto updateable = std::dynamic_pointer_cast<Updatable>(component); 00127 if (updateable){ 00128 mUpdatable.push_back(updateable); 00129 } 00130 } 00131 if (status == ComponentUpdateStatus::Destroyed){ 00132 if (camera){ 00133 auto pos = find(mCameras.begin(), mCameras.end(), camera); 00134 if (pos != mCameras.end()){ 00135 mCameras.erase(pos); 00136 } 00137 } else if (light){ 00138 // rebuild lights 00139 auto lightPos = mLights.find(light); 00140 if (lightPos != mLights.end()){ 00141 mLights.erase(lightPos); 00142 rebuildSceneLights(); 00143 } 00144 } 00145 auto updateable = std::dynamic_pointer_cast<Updatable>(component); 00146 if (updateable){ 00147 auto pos = find(mUpdatable.begin(), mUpdatable.end(), updateable); 00148 if (pos != mUpdatable.end()){ 00149 mUpdatable.erase(pos); 00150 } 00151 } 00152 } 00153 } 00154 00155 void Scene::addLight(std::shared_ptr<Light> light) { 00156 switch (light->lightType()){ 00157 case LightType::Ambient: 00158 this->mSceneLights.ambientLight = light; 00159 break; 00160 case LightType::Directional: 00161 this->mSceneLights.directionalLight = light; 00162 break; 00163 case LightType::Point: 00164 this->mSceneLights.pointLights.push_back(light); 00165 break; 00166 case LightType::Spot: 00167 // todo implement 00168 break; 00169 case LightType::Uninitialized: 00170 break; 00171 } 00172 } 00173 00174 std::shared_ptr<CameraPerspective> Scene::createPerspectiveCamera(GameObject *cameraObject){ 00175 if (!cameraObject ){ 00176 cameraObject = createGameObject("PerspectiveCamera"); 00177 } 00178 auto cam = cameraObject->addComponent<CameraPerspective>(); 00179 cam->setNear(0.1f); 00180 cam->setFar(100); 00181 cam->setFieldOfViewY(glm::radians(60.0f)); 00182 cam->setClearColor(glm::vec4(0,0,0,1)); 00183 return cam; 00184 } 00185 00186 std::shared_ptr<CameraOrthographic> Scene::createOrthographicCamera(GameObject *cameraObject) { 00187 if (!cameraObject ) { 00188 cameraObject = createGameObject("OrthographicCamera"); 00189 } 00190 auto cam = cameraObject->addComponent<CameraOrthographic>(); 00191 glm::ivec2 dim = Engine::context()->getContextSurfaceDim(); 00192 cam->setNear(-10); 00193 cam->setFar(10); 00194 cam->setLeft(-dim.x/2); 00195 cam->setRight(dim.x/2); 00196 cam->setBottom(-dim.y/2); 00197 cam->setTop(dim.y/2); 00198 cam->setClearColor(glm::vec4(0,0,0,1)); 00199 return cam; 00200 } 00201 00202 std::shared_ptr<MeshRenderer> Scene::createCube(GameObject *gameObject, float length){ 00203 if (!gameObject) { 00204 gameObject = createGameObject("Cube"); 00205 } 00206 auto meshRenderer = gameObject->addComponent<MeshRenderer>(); 00207 auto mesh = make_shared<Mesh>(); 00208 mesh->setMeshData(MeshFactory::createCubeData(length*0.5f)); 00209 meshRenderer->setMesh(mesh); 00210 00211 Material* mat = Project::createMaterial("assets/shaders/diffuse.shader"); 00212 meshRenderer->setMaterial(mat); 00213 return meshRenderer; 00214 } 00215 00216 std::shared_ptr<MeshRenderer> Scene::createSphere(GameObject *gameObject){ 00217 if (!gameObject ) { 00218 gameObject = createGameObject("Sphere"); 00219 } 00220 auto meshRenderer = gameObject->addComponent<MeshRenderer>(); 00221 auto mesh = make_shared<Mesh>(); 00222 mesh->setMeshData(MeshFactory::createUVSphereData()); 00223 meshRenderer->setMesh(mesh); 00224 00225 Material* mat = Project::createMaterial("assets/shaders/diffuse.shader"); 00226 meshRenderer->setMaterial(mat); 00227 return meshRenderer; 00228 } 00229 00230 00231 std::shared_ptr<LineRenderer> Scene::createLine(GameObject *gameObject, const vector<glm::vec3> &points, kick::MeshType meshType, const std::vector<GLushort> &indices) { 00232 if (!gameObject) { 00233 gameObject = createGameObject("Plane"); 00234 } 00235 auto lineRenderer = gameObject->addComponent<LineRenderer>(); 00236 if (points.size()){ 00237 lineRenderer->setPoints(points, meshType, indices); 00238 } 00239 return lineRenderer; 00240 } 00241 00242 std::shared_ptr<MeshRenderer> Scene::createPlane(GameObject *gameObject){ 00243 if (!gameObject) { 00244 gameObject = createGameObject("Plane"); 00245 } 00246 auto meshRenderer = gameObject->addComponent<MeshRenderer>(); 00247 auto mesh = make_shared<Mesh>(); 00248 mesh->setMeshData(MeshFactory::createPlaneData()); 00249 meshRenderer->setMesh(mesh); 00250 00251 Material* mat = Project::createMaterial("assets/shaders/diffuse.shader"); 00252 meshRenderer->setMaterial(mat); 00253 return meshRenderer; 00254 } 00255 00256 std::shared_ptr<Light> Scene::createPointLight(GameObject *gameObject){ 00257 if (!gameObject) { 00258 gameObject = createGameObject("PointLight"); 00259 } 00260 auto light = gameObject->addComponent<Light>(); 00261 light->setLightType(LightType::Point); 00262 return light; 00263 } 00264 00265 std::shared_ptr<Light> Scene::createDirectionalLight(GameObject *gameObject){ 00266 if (!gameObject){ 00267 gameObject = createGameObject("DirectionalLight"); 00268 } 00269 auto light = gameObject->addComponent<Light>(); 00270 light->setLightType(LightType::Directional); 00271 return light; 00272 } 00273 00274 // helper function, which creates a gameobject and attaches a ambient light 00275 std::shared_ptr<Light> Scene::createAmbientLight(float intensity, glm::vec3 color){ 00276 GameObject *gameObject = createGameObject("AmbientLight"); 00277 auto light = gameObject->addComponent<Light>(); 00278 light->setLightType(LightType::Ambient); 00279 light->setIntensity(intensity); 00280 light->setColor(color); 00281 return light; 00282 } 00283 00284 void Scene::rebuildSceneLights() { 00285 mSceneLights.clear(); 00286 for (auto & l : mLights){ 00287 addLight(l.first); 00288 } 00289 } 00290 00291 std::shared_ptr<Canvas> Scene::createCanvas(bool includeUICamera) { 00292 GameObject *gameObject = createGameObject("Canvas"); 00293 auto canvas = gameObject->addComponent<Canvas>(); 00294 if (includeUICamera){ 00295 auto camera = createOrthographicCamera(gameObject); 00296 camera->setMain(false); 00297 camera->setIndex(1); 00298 camera->setCullingMask(256);//0b100000000 00299 camera->setClearColorBuffer(false); 00300 canvas->setCamera(camera); 00301 } 00302 return canvas; 00303 } 00304 00305 GameObject *Scene::gameObjectByUID(int32_t uid) { 00306 for (auto & gameObject : *this) { 00307 if (gameObject->uniqueId() == uid) { 00308 return gameObject.get(); 00309 } 00310 } 00311 return nullptr; 00312 } 00313 00314 std::shared_ptr<Camera> Scene::mainCamera() { 00315 for (auto c : mCameras) { 00316 if (c->main()) { 00317 return c; 00318 } 00319 } 00320 if (!mCameras.empty()) { 00321 return mCameras[0]; 00322 } 00323 return std::shared_ptr<Camera>(); 00324 } 00325 }