Line data Source code
1 : /* Copyright (C) 2022 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "precompiled.h"
19 :
20 : #include "ActorViewer.h"
21 :
22 : #include "View.h"
23 :
24 : #include "graphics/Canvas2D.h"
25 : #include "graphics/ColladaManager.h"
26 : #include "graphics/LOSTexture.h"
27 : #include "graphics/MiniMapTexture.h"
28 : #include "graphics/Model.h"
29 : #include "graphics/ModelDef.h"
30 : #include "graphics/ObjectManager.h"
31 : #include "graphics/ParticleManager.h"
32 : #include "graphics/Patch.h"
33 : #include "graphics/SkeletonAnimManager.h"
34 : #include "graphics/Terrain.h"
35 : #include "graphics/TerrainTextureEntry.h"
36 : #include "graphics/TerrainTextureManager.h"
37 : #include "graphics/TerritoryTexture.h"
38 : #include "graphics/Unit.h"
39 : #include "graphics/UnitManager.h"
40 : #include "graphics/Overlay.h"
41 : #include "maths/MathUtil.h"
42 : #include "ps/Filesystem.h"
43 : #include "ps/CLogger.h"
44 : #include "ps/GameSetup/Config.h"
45 : #include "ps/ProfileViewer.h"
46 : #include "ps/VideoMode.h"
47 : #include "renderer/backend/IDevice.h"
48 : #include "renderer/backend/IDeviceCommandContext.h"
49 : #include "renderer/Renderer.h"
50 : #include "renderer/RenderingOptions.h"
51 : #include "renderer/Scene.h"
52 : #include "renderer/SceneRenderer.h"
53 : #include "renderer/SkyManager.h"
54 : #include "renderer/WaterManager.h"
55 : #include "scriptinterface/ScriptContext.h"
56 : #include "simulation2/Simulation2.h"
57 : #include "simulation2/components/ICmpAttack.h"
58 : #include "simulation2/components/ICmpOwnership.h"
59 : #include "simulation2/components/ICmpPosition.h"
60 : #include "simulation2/components/ICmpRangeManager.h"
61 : #include "simulation2/components/ICmpTerrain.h"
62 : #include "simulation2/components/ICmpUnitMotion.h"
63 : #include "simulation2/components/ICmpVisual.h"
64 : #include "simulation2/components/ICmpWaterManager.h"
65 : #include "simulation2/helpers/Render.h"
66 :
67 : extern int g_xres, g_yres;
68 :
69 0 : struct ActorViewerImpl : public Scene
70 : {
71 : NONCOPYABLE(ActorViewerImpl);
72 : public:
73 0 : ActorViewerImpl() :
74 : Entity(INVALID_ENTITY),
75 : Terrain(),
76 : ColladaManager(g_VFS),
77 : MeshManager(ColladaManager),
78 : SkeletonAnimManager(ColladaManager),
79 : UnitManager(),
80 0 : Simulation2(&UnitManager, g_ScriptContext, &Terrain),
81 : ObjectManager(MeshManager, SkeletonAnimManager, Simulation2),
82 : LOSTexture(Simulation2),
83 : TerritoryTexture(Simulation2),
84 0 : MiniMapTexture(Simulation2)
85 : {
86 0 : UnitManager.SetObjectManager(ObjectManager);
87 0 : }
88 :
89 : entity_id_t Entity;
90 : CStrW CurrentUnitID;
91 : CStr CurrentUnitAnim;
92 : float CurrentSpeed;
93 : bool WalkEnabled;
94 : bool GroundEnabled;
95 : bool WaterEnabled;
96 : bool ShadowsEnabled;
97 :
98 : // Whether shadows, sky and water are enabled outside of the actor viewer.
99 : bool OldShadows;
100 : bool OldSky;
101 : bool OldWater;
102 :
103 : bool SelectionBoxEnabled;
104 : bool AxesMarkerEnabled;
105 : int PropPointsMode; // 0 disabled, 1 for point markers, 2 for point markers + axes
106 :
107 : CTerrain Terrain;
108 :
109 : CColladaManager ColladaManager;
110 : CMeshManager MeshManager;
111 : CSkeletonAnimManager SkeletonAnimManager;
112 : CUnitManager UnitManager;
113 : CSimulation2 Simulation2;
114 : CObjectManager ObjectManager; // Keep this after Simulation2 - it needs it for initialisation.
115 : CLOSTexture LOSTexture;
116 : CTerritoryTexture TerritoryTexture;
117 : CMiniMapTexture MiniMapTexture;
118 :
119 : SOverlayLine SelectionBoxOverlay;
120 : SOverlayLine AxesMarkerOverlays[3];
121 : std::vector<CModel::Prop> Props;
122 : std::vector<SOverlayLine> PropPointOverlays;
123 :
124 : // Simplistic implementation of the Scene interface
125 0 : virtual void EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
126 : {
127 0 : if (GroundEnabled)
128 : {
129 0 : for (ssize_t pj = 0; pj < Terrain.GetPatchesPerSide(); ++pj)
130 0 : for (ssize_t pi = 0; pi < Terrain.GetPatchesPerSide(); ++pi)
131 0 : c->Submit(Terrain.GetPatch(pi, pj));
132 : }
133 :
134 0 : CmpPtr<ICmpVisual> cmpVisual(Simulation2, Entity);
135 0 : if (cmpVisual)
136 : {
137 : // add selection box outlines manually
138 0 : if (SelectionBoxEnabled)
139 : {
140 0 : SelectionBoxOverlay.m_Color = CColor(35/255.f, 86/255.f, 188/255.f, .75f); // pretty blue
141 0 : SelectionBoxOverlay.m_Thickness = 0.1f;
142 :
143 0 : SimRender::ConstructBoxOutline(cmpVisual->GetSelectionBox(), SelectionBoxOverlay);
144 0 : c->Submit(&SelectionBoxOverlay);
145 : }
146 :
147 : // add origin axis thingy
148 0 : if (AxesMarkerEnabled)
149 : {
150 0 : CMatrix3D worldSpaceAxes;
151 : // offset from the ground a little bit to prevent fighting with the floor texture (also note: SetTranslation
152 : // sets the identity 3x3 transformation matrix, which are the world axes)
153 0 : worldSpaceAxes.SetTranslation(cmpVisual->GetPosition() + CVector3D(0, 0.02f, 0));
154 0 : SimRender::ConstructAxesMarker(worldSpaceAxes, AxesMarkerOverlays[0], AxesMarkerOverlays[1], AxesMarkerOverlays[2]);
155 :
156 0 : c->Submit(&AxesMarkerOverlays[0]);
157 0 : c->Submit(&AxesMarkerOverlays[1]);
158 0 : c->Submit(&AxesMarkerOverlays[2]);
159 : }
160 :
161 : // add prop point overlays
162 0 : if (PropPointsMode > 0 && Props.size() > 0)
163 : {
164 0 : PropPointOverlays.clear(); // doesn't clear capacity, but should be ok since the number of prop points is usually pretty limited
165 0 : for (size_t i = 0; i < Props.size(); ++i)
166 : {
167 0 : CModel::Prop& prop = Props[i];
168 0 : if (prop.m_Model) // should always be the case
169 : {
170 : // prop point positions are automatically updated during animations etc. by CModel::ValidatePosition
171 0 : const CMatrix3D& propCoordSystem = prop.m_Model->GetTransform();
172 :
173 0 : SOverlayLine pointGimbal;
174 0 : pointGimbal.m_Color = CColor(1.f, 0.f, 1.f, 1.f);
175 0 : SimRender::ConstructGimbal(propCoordSystem.GetTranslation(), 0.05f, pointGimbal);
176 0 : PropPointOverlays.push_back(pointGimbal);
177 :
178 0 : if (PropPointsMode > 1)
179 : {
180 : // scale the prop axes coord system down a bit to distinguish them from the main world-space axes markers
181 0 : CMatrix3D displayCoordSystem = propCoordSystem;
182 0 : displayCoordSystem.Scale(0.5f, 0.5f, 0.5f);
183 : // revert translation scaling
184 0 : displayCoordSystem._14 = propCoordSystem._14;
185 0 : displayCoordSystem._24 = propCoordSystem._24;
186 0 : displayCoordSystem._34 = propCoordSystem._34;
187 :
188 : // construct an XYZ axes marker for the prop's coordinate system
189 0 : SOverlayLine xAxis, yAxis, zAxis;
190 0 : SimRender::ConstructAxesMarker(displayCoordSystem, xAxis, yAxis, zAxis);
191 0 : PropPointOverlays.push_back(xAxis);
192 0 : PropPointOverlays.push_back(yAxis);
193 0 : PropPointOverlays.push_back(zAxis);
194 : }
195 : }
196 : }
197 :
198 0 : for (size_t i = 0; i < PropPointOverlays.size(); ++i)
199 : {
200 0 : c->Submit(&PropPointOverlays[i]);
201 : }
202 : }
203 : }
204 :
205 : // send a RenderSubmit message so the components can submit their visuals to the renderer
206 0 : Simulation2.RenderSubmit(*c, frustum, false);
207 0 : }
208 :
209 0 : virtual CLOSTexture& GetLOSTexture()
210 : {
211 0 : return LOSTexture;
212 : }
213 :
214 0 : virtual CTerritoryTexture& GetTerritoryTexture()
215 : {
216 0 : return TerritoryTexture;
217 : }
218 :
219 0 : virtual CMiniMapTexture& GetMiniMapTexture()
220 : {
221 0 : return MiniMapTexture;
222 : }
223 :
224 : /**
225 : * Recursively fetches the props of the currently displayed entity model and its submodels, and stores them for rendering.
226 : */
227 : void UpdatePropList();
228 : void UpdatePropListRecursive(CModelAbstract* model);
229 :
230 : };
231 :
232 0 : void ActorViewerImpl::UpdatePropList()
233 : {
234 0 : Props.clear();
235 :
236 0 : CmpPtr<ICmpVisual> cmpVisual(Simulation2, Entity);
237 0 : if (cmpVisual)
238 : {
239 0 : CUnit* unit = cmpVisual->GetUnit();
240 0 : if (unit)
241 : {
242 0 : CModelAbstract& modelAbstract = unit->GetModel();
243 0 : UpdatePropListRecursive(&modelAbstract);
244 : }
245 : }
246 0 : }
247 :
248 0 : void ActorViewerImpl::UpdatePropListRecursive(CModelAbstract* modelAbstract)
249 : {
250 0 : ENSURE(modelAbstract);
251 :
252 0 : CModel* model = modelAbstract->ToCModel();
253 0 : if (model)
254 : {
255 0 : std::vector<CModel::Prop>& modelProps = model->GetProps();
256 0 : for (CModel::Prop& modelProp : modelProps)
257 : {
258 0 : Props.push_back(modelProp);
259 0 : if (modelProp.m_Model)
260 0 : UpdatePropListRecursive(modelProp.m_Model);
261 : }
262 : }
263 0 : }
264 :
265 0 : ActorViewer::ActorViewer()
266 0 : : m(*new ActorViewerImpl())
267 : {
268 0 : m.WalkEnabled = false;
269 0 : m.GroundEnabled = true;
270 0 : m.WaterEnabled = false;
271 0 : m.ShadowsEnabled = g_RenderingOptions.GetShadows();
272 0 : m.SelectionBoxEnabled = false;
273 0 : m.AxesMarkerEnabled = false;
274 0 : m.PropPointsMode = 0;
275 :
276 : // Create a tiny empty piece of terrain, just so we can put shadows
277 : // on it without having to think too hard
278 0 : m.Terrain.Initialize(2, NULL);
279 0 : CTerrainTextureEntry* tex = g_TexMan.FindTexture("whiteness");
280 0 : if (tex)
281 : {
282 0 : for (ssize_t pi = 0; pi < m.Terrain.GetPatchesPerSide(); ++pi)
283 : {
284 0 : for (ssize_t pj = 0; pj < m.Terrain.GetPatchesPerSide(); ++pj)
285 : {
286 0 : CPatch* patch = m.Terrain.GetPatch(pi, pj);
287 0 : for (ssize_t i = 0; i < PATCH_SIZE; ++i)
288 : {
289 0 : for (ssize_t j = 0; j < PATCH_SIZE; ++j)
290 : {
291 0 : CMiniPatch& mp = patch->m_MiniPatches[i][j];
292 0 : mp.Tex = tex;
293 0 : mp.Priority = 0;
294 : }
295 : }
296 : }
297 : }
298 : }
299 : else
300 : {
301 0 : debug_warn(L"Failed to load whiteness texture");
302 : }
303 :
304 : // Prepare the simulation
305 0 : m.Simulation2.LoadDefaultScripts();
306 0 : m.Simulation2.ResetState();
307 :
308 : // Set player data
309 0 : m.Simulation2.SetMapSettings(m.Simulation2.GetPlayerDefaults());
310 0 : m.Simulation2.LoadPlayerSettings(true);
311 :
312 : // Tell the simulation we've already loaded the terrain
313 0 : CmpPtr<ICmpTerrain> cmpTerrain(m.Simulation2, SYSTEM_ENTITY);
314 0 : if (cmpTerrain)
315 0 : cmpTerrain->ReloadTerrain(false);
316 :
317 : // Remove FOW since we're in Atlas
318 0 : CmpPtr<ICmpRangeManager> cmpRangeManager(m.Simulation2, SYSTEM_ENTITY);
319 0 : if (cmpRangeManager)
320 0 : cmpRangeManager->SetLosRevealAll(-1, true);
321 :
322 0 : m.Simulation2.InitGame();
323 0 : }
324 :
325 0 : ActorViewer::~ActorViewer()
326 : {
327 0 : delete &m;
328 0 : }
329 :
330 0 : CSimulation2* ActorViewer::GetSimulation2()
331 : {
332 0 : return &m.Simulation2;
333 : }
334 :
335 0 : entity_id_t ActorViewer::GetEntity()
336 : {
337 0 : return m.Entity;
338 : }
339 :
340 0 : void ActorViewer::UnloadObjects()
341 : {
342 0 : m.ObjectManager.UnloadObjects();
343 0 : }
344 :
345 0 : void ActorViewer::SetActor(const CStrW& name, const CStr& animation, player_id_t playerID)
346 : {
347 0 : bool needsAnimReload = false;
348 :
349 0 : CStrW id = name;
350 :
351 : // Recreate the entity, if we don't have one or if the new one is different
352 0 : if (m.Entity == INVALID_ENTITY || id != m.CurrentUnitID)
353 : {
354 : // Delete the old entity (if any)
355 0 : if (m.Entity != INVALID_ENTITY)
356 : {
357 0 : m.Simulation2.DestroyEntity(m.Entity);
358 0 : m.Simulation2.FlushDestroyedEntities();
359 0 : m.Entity = INVALID_ENTITY;
360 : }
361 :
362 : // Clear particles associated with deleted entity
363 0 : g_Renderer.GetSceneRenderer().GetParticleManager().ClearUnattachedEmitters();
364 :
365 : // If there's no actor to display, return with nothing loaded
366 0 : if (id.empty())
367 0 : return;
368 :
369 0 : m.Entity = m.Simulation2.AddEntity(L"preview|" + id);
370 0 : if (m.Entity == INVALID_ENTITY)
371 0 : return;
372 :
373 0 : CmpPtr<ICmpPosition> cmpPosition(m.Simulation2, m.Entity);
374 0 : if (cmpPosition)
375 : {
376 0 : ssize_t c = TERRAIN_TILE_SIZE * m.Terrain.GetPatchesPerSide()*PATCH_SIZE/2;
377 0 : cmpPosition->JumpTo(entity_pos_t::FromInt(c), entity_pos_t::FromInt(c));
378 0 : cmpPosition->SetYRotation(entity_angle_t::Pi());
379 : }
380 :
381 0 : CmpPtr<ICmpOwnership> cmpOwnership(m.Simulation2, m.Entity);
382 0 : if (cmpOwnership)
383 0 : cmpOwnership->SetOwner(playerID);
384 :
385 0 : needsAnimReload = true;
386 : }
387 :
388 0 : if (animation != m.CurrentUnitAnim)
389 0 : needsAnimReload = true;
390 :
391 0 : if (needsAnimReload)
392 : {
393 : // Emulate the typical simulation animation behaviour.
394 0 : CStr anim = animation.LowerCase();
395 0 : float speed = 1.0f;
396 : // Speed will be ignored if we have a repeat time.
397 0 : float repeatTime = 0.0f;
398 0 : m.CurrentSpeed = 0.0f;
399 0 : if (anim == "walk")
400 : {
401 0 : CmpPtr<ICmpUnitMotion> cmpUnitMotion(m.Simulation2, m.Entity);
402 0 : if (cmpUnitMotion)
403 0 : speed = cmpUnitMotion->GetWalkSpeed().ToFloat();
404 : else
405 0 : speed = 7.f; // Typical unit walk speed.
406 0 : m.CurrentSpeed = speed;
407 : }
408 0 : else if (anim == "run")
409 : {
410 0 : CmpPtr<ICmpUnitMotion> cmpUnitMotion(m.Simulation2, m.Entity);
411 0 : if (cmpUnitMotion)
412 0 : speed = cmpUnitMotion->GetWalkSpeed().ToFloat() * cmpUnitMotion->GetRunMultiplier().ToFloat();
413 : else
414 0 : speed = 12.f; // Typical unit run speed.
415 :
416 0 : m.CurrentSpeed = speed;
417 : }
418 0 : else if (anim.Find("attack_") == 0)
419 : {
420 0 : CmpPtr<ICmpAttack> cmpAttack(m.Simulation2, m.Entity);
421 0 : if (cmpAttack)
422 0 : for (const CStr& type : cmpAttack->GetAttackTypes())
423 0 : if (anim == "attack_" + type.LowerCase())
424 : {
425 0 : repeatTime = GetRepeatTimeByAttackType(type);
426 0 : break;
427 : }
428 : }
429 :
430 0 : CmpPtr<ICmpVisual> cmpVisual(m.Simulation2, m.Entity);
431 0 : if (cmpVisual)
432 : {
433 : // TODO: SetEntitySelection(anim)
434 0 : cmpVisual->SelectAnimation(anim, false, fixed::FromFloat(speed));
435 0 : if (repeatTime > 0.0f)
436 0 : cmpVisual->SetAnimationSyncRepeat(fixed::FromFloat(repeatTime));
437 : }
438 :
439 : // update prop list for new entity/animation (relies on needsAnimReload also getting called for entire entity changes)
440 0 : m.UpdatePropList();
441 : }
442 :
443 0 : m.CurrentUnitID = id;
444 0 : m.CurrentUnitAnim = animation;
445 : }
446 :
447 0 : void ActorViewer::SetEnabled(bool enabled)
448 : {
449 0 : if (enabled)
450 : {
451 : // Set shadows, sky and water.
452 0 : m.OldShadows = g_RenderingOptions.GetShadows();
453 0 : SetShadowsEnabled(m.ShadowsEnabled);
454 :
455 0 : m.OldSky = g_Renderer.GetSceneRenderer().GetSkyManager().IsSkyVisible();
456 0 : g_Renderer.GetSceneRenderer().GetSkyManager().SetSkyVisible(false);
457 :
458 0 : m.OldWater = g_Renderer.GetSceneRenderer().GetWaterManager().m_RenderWater;
459 0 : g_Renderer.GetSceneRenderer().GetWaterManager().m_RenderWater = m.WaterEnabled;
460 : }
461 : else
462 : {
463 : // Restore the old renderer state
464 0 : SetShadowsEnabled(m.OldShadows);
465 0 : g_Renderer.GetSceneRenderer().GetSkyManager().SetSkyVisible(m.OldSky);
466 0 : g_Renderer.GetSceneRenderer().GetWaterManager().m_RenderWater = m.OldWater;
467 : }
468 0 : }
469 :
470 0 : void ActorViewer::SetWalkEnabled(bool enabled) { m.WalkEnabled = enabled; }
471 0 : void ActorViewer::SetGroundEnabled(bool enabled) { m.GroundEnabled = enabled; }
472 0 : void ActorViewer::SetWaterEnabled(bool enabled)
473 : {
474 0 : m.WaterEnabled = enabled;
475 : // Adjust water level
476 0 : entity_pos_t waterLevel = entity_pos_t::FromFloat(enabled ? 10.f : 0.f);
477 0 : CmpPtr<ICmpWaterManager> cmpWaterManager(m.Simulation2, SYSTEM_ENTITY);
478 0 : if (cmpWaterManager)
479 0 : cmpWaterManager->SetWaterLevel(waterLevel);
480 0 : }
481 0 : void ActorViewer::SetShadowsEnabled(bool enabled) {
482 0 : g_RenderingOptions.SetShadows(enabled);
483 0 : m.ShadowsEnabled = enabled;
484 0 : }
485 0 : void ActorViewer::ToggleShadows()
486 : {
487 0 : SetShadowsEnabled(!m.ShadowsEnabled);
488 0 : }
489 0 : void ActorViewer::SetBoundingBoxesEnabled(bool enabled) { m.SelectionBoxEnabled = enabled; }
490 0 : void ActorViewer::SetAxesMarkerEnabled(bool enabled) { m.AxesMarkerEnabled = enabled; }
491 0 : void ActorViewer::SetPropPointsMode(int mode) { m.PropPointsMode = mode; }
492 :
493 0 : void ActorViewer::SetStatsEnabled(bool enabled)
494 : {
495 0 : if (enabled)
496 0 : g_ProfileViewer.ShowTable("renderer");
497 : else
498 0 : g_ProfileViewer.ShowTable("");
499 0 : }
500 :
501 0 : float ActorViewer::GetRepeatTimeByAttackType(const std::string& type) const
502 : {
503 0 : CmpPtr<ICmpAttack> cmpAttack(m.Simulation2, m.Entity);
504 0 : if (cmpAttack)
505 0 : return cmpAttack->GetRepeatTime(type);
506 :
507 0 : return 0.0f;
508 : }
509 :
510 0 : void ActorViewer::Render()
511 : {
512 : // TODO: ActorViewer should reuse CRenderer code and not duplicate it.
513 :
514 0 : CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer();
515 :
516 : // Set simulation context for rendering purposes
517 0 : sceneRenderer.SetSimulation(&m.Simulation2);
518 :
519 : // Find the centre of the interesting region, in the middle of the patch
520 : // and half way up the model (assuming there is one)
521 0 : CVector3D centre;
522 0 : CmpPtr<ICmpVisual> cmpVisual(m.Simulation2, m.Entity);
523 0 : if (cmpVisual)
524 0 : cmpVisual->GetBounds().GetCenter(centre);
525 : else
526 0 : centre.Y = 0.f;
527 0 : centre.X = centre.Z = TERRAIN_TILE_SIZE * m.Terrain.GetPatchesPerSide()*PATCH_SIZE/2;
528 :
529 0 : CCamera camera = AtlasView::GetView_Actor()->GetCamera();
530 0 : camera.m_Orientation.Translate(centre.X, centre.Y, centre.Z);
531 0 : camera.UpdateFrustum();
532 :
533 0 : sceneRenderer.SetSceneCamera(camera, camera);
534 :
535 0 : g_Renderer.BeginFrame();
536 :
537 : Renderer::Backend::IDeviceCommandContext* deviceCommandContext =
538 0 : g_Renderer.GetDeviceCommandContext();
539 :
540 0 : sceneRenderer.PrepareScene(deviceCommandContext, m);
541 :
542 : Renderer::Backend::IFramebuffer* backbuffer =
543 0 : deviceCommandContext->GetDevice()->GetCurrentBackbuffer(
544 : Renderer::Backend::AttachmentLoadOp::DONT_CARE,
545 : Renderer::Backend::AttachmentStoreOp::STORE,
546 : Renderer::Backend::AttachmentLoadOp::CLEAR,
547 0 : Renderer::Backend::AttachmentStoreOp::DONT_CARE);
548 0 : deviceCommandContext->BeginFramebufferPass(backbuffer);
549 :
550 0 : Renderer::Backend::IDeviceCommandContext::Rect viewportRect{};
551 0 : viewportRect.width = backbuffer->GetWidth();
552 0 : viewportRect.height = backbuffer->GetHeight();
553 0 : deviceCommandContext->SetViewports(1, &viewportRect);
554 :
555 0 : sceneRenderer.RenderScene(deviceCommandContext);
556 0 : sceneRenderer.RenderSceneOverlays(deviceCommandContext);
557 :
558 : {
559 0 : CCanvas2D canvas(g_xres, g_yres, g_VideoMode.GetScale(), deviceCommandContext);
560 0 : g_Logger->Render(canvas);
561 0 : g_ProfileViewer.RenderProfile(canvas);
562 : }
563 :
564 0 : deviceCommandContext->EndFramebufferPass();
565 :
566 0 : g_Renderer.EndFrame();
567 0 : }
568 :
569 0 : void ActorViewer::Update(float simFrameLength, float realFrameLength)
570 : {
571 0 : m.Simulation2.Update((int)(simFrameLength*1000));
572 0 : m.Simulation2.Interpolate(simFrameLength, 0, realFrameLength);
573 :
574 0 : if (m.WalkEnabled && m.CurrentSpeed)
575 : {
576 0 : CmpPtr<ICmpPosition> cmpPosition(m.Simulation2, m.Entity);
577 0 : if (cmpPosition)
578 : {
579 : // Move the model by speed*simFrameLength forwards
580 0 : float z = cmpPosition->GetPosition().Z.ToFloat();
581 0 : z -= m.CurrentSpeed*simFrameLength;
582 : // Wrap at the edges, so it doesn't run off into the horizon
583 0 : ssize_t c = TERRAIN_TILE_SIZE * m.Terrain.GetPatchesPerSide()*PATCH_SIZE/2;
584 0 : if (z < c - TERRAIN_TILE_SIZE*PATCH_SIZE * 0.1f)
585 0 : z = c + TERRAIN_TILE_SIZE*PATCH_SIZE * 0.1f;
586 0 : cmpPosition->JumpTo(cmpPosition->GetPosition().X, entity_pos_t::FromFloat(z));
587 : }
588 : }
589 3 : }
|