Leviathan  0.8.0.0
Leviathan game engine
Leviathan::Graphics Class Reference

#include <Graphics.h>

Classes

struct  Private
 

Public Member Functions

DLLEXPORT Graphics ()
 
DLLEXPORT ~Graphics ()
 
DLLEXPORT bool Init (AppDef *appdef)
 
DLLEXPORT void Release ()
 
DLLEXPORT bool Frame ()
 
DLLEXPORT void UpdateShownOverlays (const std::vector< bs::SPtr< bs::Texture >> &overlays)
 
DLLEXPORT bool IsVerticalUVFlipped () const
 
DLLEXPORT bs::HShader LoadShaderByName (const std::string &name)
 Finds and loads a shader with the name. More...
 
DLLEXPORT bs::HTexture LoadTextureByName (const std::string &name)
 Works the same as LoadShaderByName. More...
 
DLLEXPORT bs::HMesh LoadMeshByName (const std::string &name)
 Works the same as LoadShaderByName. More...
 
DLLEXPORT bs::HAnimationClip LoadAnimationClipByName (const std::string &name)
 Works the same as LoadShaderByName. More...
 

Protected Member Functions

bs::SPtr< bs::RenderWindow > RegisterCreatedWindow (Window &window)
 Called when Window objects are created to register them with bsf and with the case of the first window this initializes the rest of bsf. More...
 

Detailed Description

Definition at line 12 of file Graphics.h.

Constructor & Destructor Documentation

◆ Graphics()

DLLEXPORT Graphics::Graphics ( )

Definition at line 235 of file Graphics.cpp.

235 {}

◆ ~Graphics()

Graphics::~Graphics ( )

Definition at line 237 of file Graphics.cpp.

238 {
239  LEVIATHAN_ASSERT(!Initialized, "Graphics not released before destructor");
240 }
#define LEVIATHAN_ASSERT(x, msg)
Definition: Define.h:98

Member Function Documentation

◆ Frame()

DLLEXPORT bool Graphics::Frame ( )

Definition at line 538 of file Graphics.cpp.

539 {
540  // Logic for this frame is already ready, just tell bsf to render once
541 
542  // A bunch of code here is copy pasted from BsCoreApplication.cpp
543  using namespace bs;
544 
545  gProfilerCPU().beginThread("Sim");
546 
547  // This does unwanted things with X11
548  // Platform::_update();
549 
550  gTime()._update();
551  // gInput()._update();
552  // RenderWindowManager::update needs to happen after Input::update and before
553  // Input::_triggerCallbacks, so that all input is properly captured in case there is a
554  // focus change, and so that focus change is registered before input events are sent out
555  // (mouse press can result in code checking if a window is in focus, so it has to be up to
556  // date)
557  RenderWindowManager::instance()._update();
558  // gInput()._triggerCallbacks();
559  gDebug()._triggerCallbacks();
560 
561  // preUpdate();
562 
563  // Trigger fixed updates if required
564  {
565  UINT64 step;
566  const UINT32 numIterations = gTime()._getFixedUpdateStep(step);
567 
568  const float stepSeconds = step / 1000000.0f;
569  for(UINT32 i = 0; i < numIterations; i++) {
570  // fixedUpdate();
571  PROFILE_CALL(gSceneManager()._fixedUpdate(), "Scene fixed update");
572  // PROFILE_CALL(gPhysics().fixedUpdate(stepSeconds), "Physics simulation");
573 
574  gTime()._advanceFixedUpdate(step);
575  }
576  }
577 
578  PROFILE_CALL(gSceneManager()._update(), "Scene update");
579  // gAudio()._update();
580  // gPhysics().update();
581 
582  // Update plugins
583  // for(auto& pluginUpdateFunc : mPluginUpdateFunctions)
584  // pluginUpdateFunc.second();
585 
586  // postUpdate();
587 
588  PerFrameData perFrameData;
589 
590  // Evaluate animation after scene and plugin updates because the renderer will just now be
591  // displaying the animation we sent on the previous frame, and we want the scene
592  // information to match to what is displayed.
593  perFrameData.animation = AnimationManager::instance().update();
594  perFrameData.particles = ParticleManager::instance().update(*perFrameData.animation);
595 
596  // Send out resource events in case any were loaded/destroyed/modified
597  ResourceListenerManager::instance().update();
598 
599  // Trigger any renderer task callbacks (should be done before scene object update, or core
600  // sync, so objects have a chance to respond to the callback).
601  RendererManager::instance().getActive()->update();
602 
603  gSceneManager()._updateCoreObjectTransforms();
604  PROFILE_CALL(RendererManager::instance().getActive()->renderAll(perFrameData), "Render");
605 
606  // Core and sim thread run in lockstep. This will result in a larger input latency than if
607  // I was running just a single thread. Latency becomes worse if the core thread takes
608  // longer than sim thread, in which case sim thread needs to wait. Optimal solution would
609  // be to get an average difference between sim/core thread and start the sim thread a bit
610  // later so they finish at nearly the same time.
611  Pimpl->OurApp->WaitBeforeStartNextFrame();
612 
613  gCoreThread().queueCommand(
614  std::bind(&LeviathanBSFApplication::beginCoreProfiling, Pimpl->OurApp),
615  CTQF_InternalQueue);
616  gCoreThread().queueCommand(&Platform::_coreUpdate, CTQF_InternalQueue);
617  gCoreThread().queueCommand(
618  std::bind(&ct::RenderWindowManager::_update, ct::RenderWindowManager::instancePtr()),
619  CTQF_InternalQueue);
620 
621  gCoreThread().update();
622  gCoreThread().submitAll();
623 
624  gCoreThread().queueCommand(
626  CTQF_InternalQueue);
627 
628  gCoreThread().queueCommand(
629  std::bind(&ct::QueryManager::_update, ct::QueryManager::instancePtr()),
630  CTQF_InternalQueue);
631  gCoreThread().queueCommand(
632  std::bind(&LeviathanBSFApplication::endCoreProfiling, Pimpl->OurApp),
633  CTQF_InternalQueue);
634 
635  gProfilerCPU().endThread();
636  gProfiler()._update();
637 
638  // At this point I think it is possible that a rendering operation is going on in the
639  // background, but hopefully it is safe to execute game logic
640  return true;
641 }
void frameRenderingFinishedCallback()
Definition: Graphics.cpp:171
Definition: SFMLPackets.h:18

◆ Init()

bool Graphics::Init ( AppDef appdef)

Definition at line 242 of file Graphics.cpp.

243 {
244  // StartUp SDL //
245  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) != 0) {
246 
247  LOG_ERROR("Graphics: Init: SDL init failed, error: " + std::string(SDL_GetError()));
248  return false;
249  }
250 
251  SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
252 
253  int displays = SDL_GetNumVideoDisplays();
254 
255  LOG_INFO("SDL: display count: " + Convert::ToString(displays));
256 
257  // Get display positions
258  std::vector<SDL_Rect> displayBounds;
259 
260  for(int i = 0; i < displays; i++) {
261 
262  displayBounds.push_back(SDL_Rect());
263 
264  SDL_GetDisplayBounds(i, &displayBounds.back());
265 
266  const char* nameptr = SDL_GetDisplayName(i);
267 
268  const auto name = nameptr ? std::string(nameptr) : std::string("unnamed");
269 
270  // Video modes //
271  int videomodecount = SDL_GetNumDisplayModes(i);
272 
273  std::vector<std::string> videomodes;
274 
275  for(int a = 0; a < videomodecount; a++) {
276 
277 
278  SDL_DisplayMode mode = {SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0};
279 
280  if(SDL_GetDisplayMode(i, a, &mode) == 0) {
281 
282  videomodes.push_back(Convert::ToString(SDL_BITSPERPIXEL(mode.format)) +
283  " bpp " + Convert::ToString(mode.w) + "x" +
284  Convert::ToString(mode.h) + " at " +
285  Convert::ToString(mode.refresh_rate) + "Hz");
286  }
287  }
288 
289 
290  LOG_INFO("Display(" + Convert::ToString(i) + ", " + name + "): top left: (" +
291  Convert::ToString(displayBounds.back().x) + ", " +
292  Convert::ToString(displayBounds.back().y) +
293  ") size: " + Convert::ToString(displayBounds.back().w) + "x" +
294  Convert::ToString(displayBounds.back().h));
295 
296  // LOG_INFO("Supported modes(" + Convert::ToString(videomodes.size()) + "): ");
297  // for(const auto& mode : videomodes){
298 
299  // LOG_WRITE(" " + mode);
300  // }
301  }
302 
303 
304  if(!InitializeBSF(appdef)) {
305 
306  Logger::Get()->Error("Graphics: Init: failed to create bs::framework renderer");
307  return false;
308  }
309 
310 #ifdef __linux
311  // Set X11 error handler to not crash on non-fatal errors
312  XSetErrorHandler(LeviathanX11ErrorHandler);
313 #endif
314 
315  Initialized = true;
316  return true;
317 }
#define LOG_INFO(x)
Definition: Define.h:88
#define LOG_ERROR(x)
Definition: Define.h:90
STL namespace.
static std::string ToString(const T &val)
Definition: Convert.h:72
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
DLLEXPORT void Error(const std::string &data) override
Definition: Logger.cpp:177

◆ IsVerticalUVFlipped()

DLLEXPORT bool Graphics::IsVerticalUVFlipped ( ) const

Definition at line 662 of file Graphics.cpp.

663 {
664  const auto capabilities = bs::ct::RenderAPI::instance().getCapabilities(0);
665 
666  return capabilities.conventions.ndcYAxis != bs::Conventions::Axis::Down;
667 }

◆ LoadAnimationClipByName()

DLLEXPORT bs::HAnimationClip Graphics::LoadAnimationClipByName ( const std::string &  name)

Works the same as LoadShaderByName.

Definition at line 742 of file Graphics.cpp.

743 {
745  // Leviathan::StringOperations::RemoveExtension(name, true),
747  // Leviathan::StringOperations::GetExtension(name)
748  "asset");
749 
750  if(file.empty()) {
751  LOG_ERROR(
752  "Graphics: LoadAnimationClipByName: could not find resource with name: " + name);
753  return nullptr;
754  }
755 
756  // bs::HMesh mesh = bs::gImporter().import<bs::HMesh>(file.c_str());
757  bs::HAnimationClip animationClip = bs::gResources().load<bs::AnimationClip>(file.c_str());
758 
759  if(!animationClip) {
760  LOG_ERROR("Graphics: loading asset failed: " + name);
761  }
762 
763  return animationClip;
764 }
static const StringTypeN RemovePath(const StringTypeN &filepath)
#define LOG_ERROR(x)
Definition: Define.h:90
static DLLEXPORT FileSystem * Get()
Definition: FileSystem.cpp:74
DLLEXPORT std::string SearchForFile(FILEGROUP which, const std::string &name, const std::string &extensions, bool searchall=true)
Searches for a file.
Definition: FileSystem.cpp:666

◆ LoadMeshByName()

DLLEXPORT bs::HMesh Graphics::LoadMeshByName ( const std::string &  name)

Works the same as LoadShaderByName.

Definition at line 719 of file Graphics.cpp.

720 {
722  // Leviathan::StringOperations::RemoveExtension(name, true),
724  // Leviathan::StringOperations::GetExtension(name)
725  "asset");
726 
727  if(file.empty()) {
728  LOG_ERROR("Graphics: LoadMeshByName: could not find resource with name: " + name);
729  return nullptr;
730  }
731 
732  // bs::HMesh mesh = bs::gImporter().import<bs::HMesh>(file.c_str());
733  bs::HMesh mesh = bs::gResources().load<bs::Mesh>(file.c_str());
734 
735  if(!mesh) {
736  LOG_ERROR("Graphics: loading asset failed: " + name);
737  }
738 
739  return mesh;
740 }
static const StringTypeN RemovePath(const StringTypeN &filepath)
#define LOG_ERROR(x)
Definition: Define.h:90
static DLLEXPORT FileSystem * Get()
Definition: FileSystem.cpp:74
DLLEXPORT std::string SearchForFile(FILEGROUP which, const std::string &name, const std::string &extensions, bool searchall=true)
Searches for a file.
Definition: FileSystem.cpp:666

◆ LoadShaderByName()

DLLEXPORT bs::HShader Graphics::LoadShaderByName ( const std::string &  name)

Finds and loads a shader with the name.

If a full path or a valid relative path is specified a full search is not done. Unless a variant of the name with ".asset" is found, which is preferred to skip expensive importing.

Definition at line 671 of file Graphics.cpp.

672 {
673  // TODO: .asset detection
674 
676  // Leviathan::StringOperations::RemoveExtension(name, true),
678  // Leviathan::StringOperations::GetExtension(name)
679  "asset");
680 
681  if(file.empty()) {
682  LOG_ERROR("Graphics: LoadShaderByName: could not find resource with name: " + name);
683  return nullptr;
684  }
685 
686  // bs::HShader shader = bs::gImporter().import<bs::Shader>(file.c_str());
687  bs::HShader shader = bs::gResources().load<bs::Shader>(file.c_str());
688 
689  if(!shader) {
690  LOG_ERROR("Graphics: loading asset failed: " + name);
691  }
692 
693  return shader;
694 }
static const StringTypeN RemovePath(const StringTypeN &filepath)
#define LOG_ERROR(x)
Definition: Define.h:90
static DLLEXPORT FileSystem * Get()
Definition: FileSystem.cpp:74
DLLEXPORT std::string SearchForFile(FILEGROUP which, const std::string &name, const std::string &extensions, bool searchall=true)
Searches for a file.
Definition: FileSystem.cpp:666

◆ LoadTextureByName()

DLLEXPORT bs::HTexture Graphics::LoadTextureByName ( const std::string &  name)

Works the same as LoadShaderByName.

Definition at line 696 of file Graphics.cpp.

697 {
699  // Leviathan::StringOperations::RemoveExtension(name, true),
701  // Leviathan::StringOperations::GetExtension(name)
702  "asset");
703 
704  if(file.empty()) {
705  LOG_ERROR("Graphics: LoadTextureByName: could not find resource with name: " + name);
706  return nullptr;
707  }
708 
709  // bs::HTexture texture = bs::gImporter().import<bs::Texture>(file.c_str());
710  bs::HTexture texture = bs::gResources().load<bs::Texture>(file.c_str());
711 
712  if(!texture) {
713  LOG_ERROR("Graphics: loading asset failed: " + name);
714  }
715 
716  return texture;
717 }
static const StringTypeN RemovePath(const StringTypeN &filepath)
#define LOG_ERROR(x)
Definition: Define.h:90
static DLLEXPORT FileSystem * Get()
Definition: FileSystem.cpp:74
DLLEXPORT std::string SearchForFile(FILEGROUP which, const std::string &name, const std::string &extensions, bool searchall=true)
Searches for a file.
Definition: FileSystem.cpp:666

◆ RegisterCreatedWindow()

bs::SPtr< bs::RenderWindow > Graphics::RegisterCreatedWindow ( Window window)
protected

Called when Window objects are created to register them with bsf and with the case of the first window this initializes the rest of bsf.

Definition at line 394 of file Graphics.cpp.

395 {
396  if(FirstWindowCreated) {
397  // Register secondary window
398  // TODO: second window setup
399  DEBUG_BREAK;
400  return nullptr;
401 
402  } else {
403  // Finish initializing graphics
404  FirstWindowCreated = true;
405  LOG_INFO("Graphics: doing bs::framework initialization after creating first window");
406 
407  // Setup first window properties
408  auto& windowDesc = Pimpl->Description.primaryWindowDesc;
409  windowDesc.depthBuffer = true;
410 
411  int multiSample;
412 
413  ObjectFileProcessor::LoadValueFromNamedVars<int>(
414  Engine::Get()->GetDefinition()->GetValues(), "WindowMultiSampleCount", multiSample,
415  1);
416 
417  windowDesc.multisampleCount = multiSample;
418  // windowDesc.multisampleHint = "";
419  // Not sure what all settings need to be copied
420  windowDesc.fullscreen = /* window.IsFullScreen() */ false;
421  windowDesc.vsync = false;
422 
423  // Fill video mode info from SDL
424  SDL_DisplayMode dm;
425  if(SDL_GetDesktopDisplayMode(0, &dm) != 0) {
426  LOG_ERROR("Graphics: RegisterCreatedWindow: failed to get desktop display mode:" +
427  std::string(SDL_GetError()));
428  return nullptr;
429  }
430 
431  int32_t width, height;
432  window.GetSize(width, height);
433  windowDesc.videoMode = bs::VideoMode(width, height, dm.refresh_rate, 0);
434 
435 #ifdef _WIN32
436  windowDesc.platformSpecific["externalWindowHandle"] =
437  std::to_string((uint64_t)window.GetNativeHandle());
438 #else
439  windowDesc.platformSpecific["externalWindowHandle"] =
440  std::to_string(window.GetNativeHandle());
441 
442  windowDesc.platformSpecific["externalDisplay"] =
443  std::to_string(window.GetWindowXDisplay());
444 #endif
445 
446  bs::CoreApplication::startUp<LeviathanBSFApplication>(Pimpl->Description);
447 
448  Pimpl->OurApp =
449  static_cast<LeviathanBSFApplication*>(bs::CoreApplication::instancePtr());
450 
451  bs::SPtr<bs::RenderWindow> bsWindow =
452  bs::CoreApplication::instance().getPrimaryWindow();
453 
454  LEVIATHAN_ASSERT(bsWindow, "window creation failed");
455 
456  // Code from BsApplication.cpp
457  using namespace bs;
458 
459  PlainTextImporter* importer = bs_new<PlainTextImporter>();
460  Importer::instance()._registerAssetImporter(importer);
461 
462  // VirtualInput::startUp();
463  BuiltinResources::startUp();
464  RendererMaterialManager::startUp();
465  RendererManager::instance().initialize();
466  SpriteManager::startUp();
467  // GUIManager::startUp();
468  // ShortcutManager::startUp();
469 
470  // bs::Cursor::startUp();
471  // bs::Cursor::instance().setCursor(CursorType::Arrow);
472  // Platform::setIcon(BuiltinResources::instance().getFrameworkIcon());
473 
474  SceneManager::instance().setMainRenderTarget(bsWindow);
475  DebugDraw::startUp();
476 
477  // startUpScriptManager();
478 
479 
480  // Notify engine to register threads to work with Ogre //
481  // Engine::GetEngine()->_NotifyThreadsRegisterOgre();
482 
483  auto shader =
484  bs::gImporter().import<bs::Shader>("Data/Shaders/CoreShaders/ScreenSpaceGUI.bsl");
485 
486  auto material = bs::Material::create(shader);
487 
488  Pimpl->OurApp->GUIRenderer =
489  RendererExtension::create<GUIOverlayRenderer>(GUIOverlayInitializationData{
490  GeometryHelpers::CreateScreenSpaceQuad(-1, -1, 2, 2)->getCore(),
491  material->getCore()});
492 
493  return bsWindow;
494  }
495 }
static DLLEXPORT bs::HMesh CreateScreenSpaceQuad(float x, float y, float width, float height, bool autoflipUV=true)
Creates a screen space plane with UV coordinates.
DLLEXPORT unsigned long GetNativeHandle() const
Definition: Window.cpp:915
DLLEXPORT void GetSize(int32_t &width, int32_t &height) const
Definition: Window.cpp:894
#define LOG_INFO(x)
Definition: Define.h:88
#define LOG_ERROR(x)
Definition: Define.h:90
DLLEXPORT NamedVars * GetValues()
Definition: AppDefine.cpp:40
Definition: SFMLPackets.h:18
#define LEVIATHAN_ASSERT(x, msg)
Definition: Define.h:98
AppDef * GetDefinition()
Definition: Engine.h:205
static DLLEXPORT Engine * Get()
Definition: Engine.cpp:85

◆ Release()

DLLEXPORT void Graphics::Release ( )

Definition at line 319 of file Graphics.cpp.

320 {
321  if(Initialized) {
322 
323  ShutdownBSF();
324 
325  SDL_Quit();
326  }
327 
328  Initialized = false;
329  FirstWindowCreated = false;
330  Pimpl.reset();
331 }

◆ UpdateShownOverlays()

DLLEXPORT void Graphics::UpdateShownOverlays ( const std::vector< bs::SPtr< bs::Texture >> &  overlays)

Definition at line 643 of file Graphics.cpp.

645 {
646  std::vector<bs::SPtr<bs::ct::Texture>> coreVersion;
647  coreVersion.reserve(overlays.size());
648 
649  std::transform(overlays.begin(), overlays.end(), std::back_inserter(coreVersion),
650  [](const bs::SPtr<bs::Texture>& item) { return item->getCore(); });
651 
652  std::weak_ptr<GUIOverlayRenderer> rendererExtension = Pimpl->OurApp->GUIRenderer;
653 
654  bs::gCoreThread().queueCommand(
655  [rendererExtension, coreVersion = std::move(coreVersion)]() {
656  const auto locked = rendererExtension.lock();
657  if(locked)
658  locked->UpdateShownOverlays(coreVersion);
659  });
660 }

The documentation for this class was generated from the following files: