diff --git a/doomsday/client/include/render/skydrawable.h b/doomsday/client/include/render/skydrawable.h index 7b163fb88a..2a30685f85 100644 --- a/doomsday/client/include/render/skydrawable.h +++ b/doomsday/client/include/render/skydrawable.h @@ -43,13 +43,10 @@ class Sky; class SkyDrawable { public: - /// No animator is presently configured. @ingroup errors - DENG2_ERROR(MissingAnimatorError); - /// Required model is missing. @ingroup errors DENG2_ERROR(MissingModelError); - struct ModelInfo + struct ModelData { de::Record const *def; // Sky model def ModelDef *model; @@ -88,10 +85,6 @@ class SkyDrawable public: SkyDrawable(); - bool hasAnimator() const; - void setAnimator(Animator *newAnimator); - Animator &animator(); - /** * Models are set up according to the given @a skyDef. */ @@ -100,12 +93,12 @@ class SkyDrawable /** * Cache all assets needed for visualizing the sky. */ - void cacheDrawableAssets(); + void cacheDrawableAssets(Sky const *sky = 0); /** * Render the sky. */ - void draw(); + void draw(Sky const *sky = 0) const; /** * Determines whether the specified sky model @a index is valid. @@ -119,21 +112,17 @@ class SkyDrawable * * @see hasModel() */ - ModelInfo &model(int index); + ModelData &model(int index); /// @copydoc model() - ModelInfo const &model(int index) const; + ModelData const &model(int index) const; /** * Returns a pointer to the referenced sky model; otherwise @c 0. * * @see hasModel(), model() */ - inline ModelInfo *modelPtr(int index) { return hasModel(index)? &model(index) : 0; } - - /// @todo RenderSystem should own a sky-masked-material => SkyDrawable map. - void setSky(Sky *sky); - Sky &sky(); + inline ModelData *modelPtr(int index) { return hasModel(index)? &model(index) : 0; } public: static de::MaterialVariantSpec const &layerMaterialSpec(bool masked); diff --git a/doomsday/client/include/world/p_ticker.h b/doomsday/client/include/world/p_ticker.h index 323c299ccf..3f6cf29145 100644 --- a/doomsday/client/include/world/p_ticker.h +++ b/doomsday/client/include/world/p_ticker.h @@ -20,6 +20,10 @@ #ifndef DENG_WORLD_P_TICKER_H #define DENG_WORLD_P_TICKER_H +#include "world/thinkers.h" + +int P_MobjTicker(thinker_t *th, void *context); + /** * Doomsday's own play-ticker. */ diff --git a/doomsday/client/include/world/worldsystem.h b/doomsday/client/include/world/worldsystem.h index 0c7d532a5c..cc10a2d290 100644 --- a/doomsday/client/include/world/worldsystem.h +++ b/doomsday/client/include/world/worldsystem.h @@ -74,10 +74,6 @@ class WorldSystem : public de::System // System. void timeChanged(de::Clock const &); - /** - * To be called to register the commands and variables of this module. - */ - static void consoleRegister(); /** * To be called to reset the world back to the initial state. Any currently @@ -131,6 +127,8 @@ class WorldSystem : public de::System */ timespan_t time() const; + void tick(timespan_t elapsed); + #ifdef __CLIENT__ /** * To be called at the beginning of a render frame, so that we can prepare for @@ -164,6 +162,12 @@ class WorldSystem : public de::System #endif // __CLIENT__ +public: + /** + * To be called to register the commands and variables of this module. + */ + static void consoleRegister(); + private: DENG2_PRIVATE(d) }; diff --git a/doomsday/client/src/render/rend_main.cpp b/doomsday/client/src/render/rend_main.cpp index 3848a1d244..952eea217f 100644 --- a/doomsday/client/src/render/rend_main.cpp +++ b/doomsday/client/src/render/rend_main.cpp @@ -3465,7 +3465,7 @@ static void drawLists(DrawLists::FoundLists const &lists, DrawMode mode) popGLStateForPass(mode); } -static void drawSky() +static void drawSky(Sky const &sky) { DrawLists::FoundLists lists; ClientApp::renderSystem().drawLists().findAll(SkyMaskGeom, lists); @@ -3503,7 +3503,7 @@ static void drawSky() glStencilFunc(GL_EQUAL, 1, 0xffffffff); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - ClientApp::renderSystem().sky().draw(); + ClientApp::renderSystem().sky().draw(&sky); if(!devRendSkyAlways) { @@ -3634,7 +3634,7 @@ static void drawAllLists(Map &map) DENG_ASSERT_IN_MAIN_THREAD(); DENG_ASSERT_GL_CONTEXT_ACTIVE(); - drawSky(); + drawSky(map.sky()); // Render the real surfaces of the visible world. diff --git a/doomsday/client/src/render/rendersystem.cpp b/doomsday/client/src/render/rendersystem.cpp index 7906b26411..a2c08fb4e7 100644 --- a/doomsday/client/src/render/rendersystem.cpp +++ b/doomsday/client/src/render/rendersystem.cpp @@ -90,10 +90,7 @@ uint Store::allocateVertices(uint count) DENG2_PIMPL(RenderSystem) { ModelRenderer models; - SkyDrawable sky; - SkyDrawable::Animator skyAnimator; - SettingsRegister settings; SettingsRegister appearanceSettings; ImageBank images; @@ -222,9 +219,6 @@ DENG2_PIMPL(RenderSystem) .define(SReg::IntCVar, "rend-particle-visible-near", 0) .define(SReg::FloatCVar, "rend-sky-distance", 1600); - - skyAnimator.setSky(&sky); - sky.setAnimator(&skyAnimator); } /** diff --git a/doomsday/client/src/render/skydrawable.cpp b/doomsday/client/src/render/skydrawable.cpp index 6bb2f29ac7..fc44f1c1dd 100644 --- a/doomsday/client/src/render/skydrawable.cpp +++ b/doomsday/client/src/render/skydrawable.cpp @@ -165,7 +165,7 @@ static void makeHemisphere(float height, float horizonOffset) } } -static void rebuildHemisphereIfNeeded(Sky &sky) +static void rebuildHemisphereIfNeeded(Sky const &sky) { static bool firstBuild = true; static float oldHorizonOffset; @@ -191,7 +191,7 @@ static void rebuildHemisphereIfNeeded(Sky &sky) makeHemisphere(sky.height(), sky.horizonOffset()); } -static void configureSphereDrawState(Sky &sky, int layerIndex, hemispherecap_t setupCap) +static void configureSphereDrawState(Sky const &sky, int layerIndex, hemispherecap_t setupCap) { // Default state is no texture and no fadeout. ds.texSize = Vector2i(); @@ -261,7 +261,7 @@ static void configureSphereDrawState(Sky &sky, int layerIndex, hemispherecap_t s } /// @param flags @ref skySphereRenderFlags -static void drawHemisphere(Sky &sky, SphereComponentFlags flags) +static void drawHemisphere(Sky const &sky, SphereComponentFlags flags) { int const firstLayer = sky.firstActiveLayer(); DENG2_ASSERT(firstLayer >= 0); @@ -360,24 +360,20 @@ using namespace ::internal; DENG2_PIMPL(SkyDrawable) { - Animator *animator = nullptr; - - ModelInfo models[MAX_SKY_MODELS]; + ModelData models[MAX_SKY_MODELS]; bool haveModels = false; bool alwaysDrawSphere = false; - Sky *sky = 0; - Instance(Public *i) : Base(i) { de::zap(models); } - inline ResourceSystem &resSys() { + static inline ResourceSystem &resSys() { return ClientApp::resourceSystem(); } - void drawSphere() + void drawSphere(Sky const &sky) const { if(haveModels && !alwaysDrawSphere) return; @@ -395,8 +391,8 @@ DENG2_PIMPL(SkyDrawable) glScalef(skyDistance, skyDistance, skyDistance); // Always draw both hemispheres. - drawHemisphere(self.sky(), LowerHemisphere); - drawHemisphere(self.sky(), UpperHemisphere); + drawHemisphere(sky, LowerHemisphere); + drawHemisphere(sky, UpperHemisphere); glMatrixMode(GL_MODELVIEW); glPopMatrix(); @@ -408,7 +404,7 @@ DENG2_PIMPL(SkyDrawable) glEnable(GL_DEPTH_TEST); } - void drawModels() + void drawModels(Sky const &sky) const { if(!haveModels) return; @@ -424,13 +420,13 @@ DENG2_PIMPL(SkyDrawable) for(int i = 0; i < MAX_SKY_MODELS; ++i) { - ModelInfo &minfo = models[i]; - Record const *skyModelDef = minfo.def; + ModelData const &mdata = models[i]; + Record const *skyModelDef = mdata.def; if(!skyModelDef) continue; // If the associated sky layer is not active then the model won't be drawn. - if(!sky->layer(skyModelDef->geti("layer")).isActive()) + if(!sky.layer(skyModelDef->geti("layer")).isActive()) { continue; } @@ -442,16 +438,16 @@ DENG2_PIMPL(SkyDrawable) vis.pose.distance = 1; Vector2f rotate(skyModelDef->get("rotate")); - vis.pose.yaw = minfo.yaw; + vis.pose.yaw = mdata.yaw; vis.pose.extraYawAngle = vis.pose.yawAngleOffset = rotate.x; vis.pose.extraPitchAngle = vis.pose.pitchAngleOffset = rotate.y; drawmodelparams_t &visModel = *VS_MODEL(&vis); - visModel.inter = (minfo.maxTimer > 0 ? minfo.timer / float(minfo.maxTimer) : 0); - visModel.mf = minfo.model; + visModel.inter = (mdata.maxTimer > 0 ? mdata.timer / float(mdata.maxTimer) : 0); + visModel.mf = mdata.model; visModel.alwaysInterpolate = true; visModel.shineTranslateWithViewerPos = true; - App_ResourceSystem().setModelDefFrame(*minfo.model, minfo.frame); + resSys().setModelDefFrame(*mdata.model, mdata.frame); vis.light.ambientColor = Vector4f(skyModelDef->get("color"), 1); @@ -485,13 +481,13 @@ void SkyDrawable::setupModels(defn::Sky const &def) for(int i = 0; i < def.modelCount(); ++i) { Record const &modef = def.model(i); - ModelInfo *minfo = &d->models[i]; + ModelData *mdata = &d->models[i]; // Is the model ID set? try { - minfo->model = &App_ResourceSystem().modelDef(modef.gets("id")); - if(!minfo->model->subCount()) + mdata->model = &d->resSys().modelDef(modef.gets("id")); + if(!mdata->model->subCount()) { continue; } @@ -499,10 +495,10 @@ void SkyDrawable::setupModels(defn::Sky const &def) // There is a model here. d->haveModels = true; - minfo->def = modef.accessedRecordPtr(); - minfo->maxTimer = int(TICSPERSEC * modef.getf("frameInterval")); - minfo->yaw = modef.getf("yaw"); - minfo->frame = minfo->model->subModelDef(0).frame; + mdata->def = modef.accessedRecordPtr(); + mdata->maxTimer = int(TICSPERSEC * modef.getf("frameInterval")); + mdata->yaw = modef.getf("yaw"); + mdata->frame = mdata->model->subModelDef(0).frame; } catch(ResourceSystem::MissingModelDefError const &) {} // Ignore this error. @@ -514,7 +510,7 @@ bool SkyDrawable::hasModel(int index) const return (index >= 0 && index < MAX_SKY_MODELS); } -SkyDrawable::ModelInfo &SkyDrawable::model(int index) +SkyDrawable::ModelData &SkyDrawable::model(int index) { if(hasModel(index)) { @@ -524,16 +520,18 @@ SkyDrawable::ModelInfo &SkyDrawable::model(int index) throw MissingModelError("SkyDrawable::model", "Invalid model index #" + String::number(index) + "."); } -SkyDrawable::ModelInfo const &SkyDrawable::model(int index) const +SkyDrawable::ModelData const &SkyDrawable::model(int index) const { - return const_cast(const_cast(this)->model(index)); + return const_cast(const_cast(this)->model(index)); } -void SkyDrawable::cacheDrawableAssets() +void SkyDrawable::cacheDrawableAssets(Sky const *sky) { + DENG2_ASSERT(sky); + for(int i = 0; i < MAX_SKY_LAYERS; ++i) { - Sky::Layer const &lyr = sky().layer(i); + Sky::Layer const &lyr = sky->layer(i); if(Material *mat = lyr.material()) { d->resSys().cache(*mat, layerMaterialSpec(lyr.isMasked())); @@ -544,61 +542,34 @@ void SkyDrawable::cacheDrawableAssets() { for(int i = 0; i < MAX_SKY_MODELS; ++i) { - ModelInfo &minfo = d->models[i]; - if(!minfo.def) continue; + ModelData &mdata = d->models[i]; + if(!mdata.def) continue; - d->resSys().cache(minfo.model); + d->resSys().cache(mdata.model); } } } -void SkyDrawable::draw() +void SkyDrawable::draw(Sky const *sky) const { - DENG_ASSERT_IN_MAIN_THREAD(); + DENG2_ASSERT(sky); + DENG2_ASSERT_IN_MAIN_THREAD(); DENG_ASSERT_GL_CONTEXT_ACTIVE(); // The sky is only drawn when at least one layer is active. - if(sky().firstActiveLayer() < 0) return; + if(sky->firstActiveLayer() < 0) return; if(usingFog) glEnable(GL_FOG); - d->drawSphere(); - d->drawModels(); + d->drawSphere(*sky); + d->drawModels(*sky); if(usingFog) glDisable(GL_FOG); } -bool SkyDrawable::hasAnimator() const -{ - return d->animator != 0; -} - -void SkyDrawable::setAnimator(Animator *newAnimator) -{ - d->animator = newAnimator; -} - -SkyDrawable::Animator &SkyDrawable::animator() -{ - if(d->animator) return *d->animator; - /// @throw MissingAnimatorError No animator is presently configured. - throw MissingAnimatorError("SkyDrawable::animator", "Missing animator"); -} - -void SkyDrawable::setSky(Sky *sky) -{ - d->sky = sky; -} - -Sky &SkyDrawable::sky() -{ - DENG2_ASSERT(d->sky); - return *d->sky; -} - MaterialVariantSpec const &SkyDrawable::layerMaterialSpec(bool masked) // static { - return ClientApp::resourceSystem() + return Instance::resSys() .materialSpec(SkySphereContext, TSF_NO_COMPRESSION | (masked? TSF_ZEROMASK : 0), 0, 0, 0, GL_REPEAT, GL_CLAMP_TO_EDGE, 0, -1, -1, false, true, false, false); @@ -665,20 +636,20 @@ void SkyDrawable::Animator::advanceTime(timespan_t /*elapsed*/) // Animate models. for(int i = 0; i < MAX_SKY_MODELS; ++i) { - ModelInfo &minfo = sky().model(i); - if(!minfo.def) continue; + ModelData &mdata = sky().model(i); + if(!mdata.def) continue; // Rotate the model. - minfo.yaw += minfo.def->getf("yawSpeed") / TICSPERSEC; + mdata.yaw += mdata.def->getf("yawSpeed") / TICSPERSEC; // Is it time to advance to the next frame? - if(minfo.maxTimer > 0 && ++minfo.timer >= minfo.maxTimer) + if(mdata.maxTimer > 0 && ++mdata.timer >= mdata.maxTimer) { - minfo.frame++; - minfo.timer = 0; + mdata.frame++; + mdata.timer = 0; // Execute a console command? - String const execute = minfo.def->gets("execute"); + String const execute = mdata.def->gets("execute"); if(!execute.isEmpty()) { Con_Execute(CMDS_SCRIPT, execute.toUtf8().constData(), true, false); diff --git a/doomsday/client/src/render/viewports.cpp b/doomsday/client/src/render/viewports.cpp index 2c29d07a49..908c639690 100644 --- a/doomsday/client/src/render/viewports.cpp +++ b/doomsday/client/src/render/viewports.cpp @@ -1157,7 +1157,7 @@ DENG_EXTERN_C void R_SkyParams(int layerIndex, int param, void * /*data*/) return; } - Sky &sky = ClientApp::renderSystem().sky().sky(); + Sky &sky = ClientApp::worldSystem().map().sky(); if(sky.hasLayer(layerIndex)) { Sky::Layer &layer = sky.layer(layerIndex); diff --git a/doomsday/client/src/world/p_ticker.cpp b/doomsday/client/src/world/p_ticker.cpp index f05e25c879..80e931df0c 100644 --- a/doomsday/client/src/world/p_ticker.cpp +++ b/doomsday/client/src/world/p_ticker.cpp @@ -18,6 +18,8 @@ */ #include "de_base.h" +#include "world/p_ticker.h" + #include "de_network.h" #include "de_render.h" #include "de_play.h" @@ -28,7 +30,6 @@ # include "render/skydrawable.h" #endif #include "world/map.h" -#include "world/thinkers.h" #include "world/sky.h" using namespace de; @@ -118,23 +119,8 @@ static void materialsTicker(timespan_t elapsed) void P_Ticker(timespan_t elapsed) { P_ControlTicker(elapsed); - #ifdef __CLIENT__ materialsTicker(elapsed); - - SkyDrawable &sky = ClientApp::renderSystem().sky(); - if(sky.hasAnimator()) - { - sky.animator().advanceTime(elapsed); - } #endif - - if(App_WorldSystem().hasMap() && DD_IsSharpTick()) - { - Map &map = App_WorldSystem().map(); - - // Check all mobjs (always public). - map.thinkers().iterate(reinterpret_cast(gx.MobjThinker), 0x1, - P_MobjTicker); - } + App_WorldSystem().tick(elapsed); } diff --git a/doomsday/client/src/world/worldsystem.cpp b/doomsday/client/src/world/worldsystem.cpp index 41fc21523d..36d0847de9 100644 --- a/doomsday/client/src/world/worldsystem.cpp +++ b/doomsday/client/src/world/worldsystem.cpp @@ -62,6 +62,7 @@ # include "server/sv_pool.h" #endif +#include "world/p_ticker.h" #include "world/sky.h" #include "world/thinkers.h" @@ -288,6 +289,7 @@ DENG2_PIMPL(WorldSystem) timespan_t time = 0; ///< World-wide time. #ifdef __CLIENT__ std::unique_ptr hand; ///< For map editing/manipulation. + SkyDrawable::Animator skyAnimator; #endif Instance(Public *i) : Base(i) @@ -495,7 +497,7 @@ DENG2_PIMPL(WorldSystem) #ifdef __CLIENT__ // Set up the SkyDrawable to get its config from the map's Sky. - ClientApp::renderSystem().sky().setSky(&map->sky()); + skyAnimator.setSky(&ClientApp::renderSystem().sky()); // Reconfigure the sky. defn::Sky skyDef; @@ -882,6 +884,22 @@ timespan_t WorldSystem::time() const return d->time; } +void WorldSystem::tick(timespan_t elapsed) +{ +#ifdef __CLIENT__ + d->skyAnimator.advanceTime(elapsed); +#else + DENG2_UNUSED(elapsed); +#endif + + if(DD_IsSharpTick() && d->map) + { + // Check all mobjs (always public). + d->map->thinkers().iterate(reinterpret_cast(gx.MobjThinker), 0x1, + P_MobjTicker); + } +} + #ifdef __CLIENT__ Hand &WorldSystem::hand(coord_t *distance) const {