<commit_before>#pragma once

#include <memory>
#include <optional>
#include <unordered_map>
#include <vector>

#include "DNACommon/CMDL.hpp"
#include "DNAMP1/CMDLMaterials.hpp"
#include "Runtime/CFactoryMgr.hpp"
#include "Runtime/CToken.hpp"
#include "Runtime/RetroTypes.hpp"
#include "Shaders/CModelShaders.hpp"

#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
#include <hecl/HMDLMeta.hpp>
#include <zeus/CAABox.hpp>
#include <zeus/CColor.hpp>

namespace urde {
class CLight;
class CModel;
class CPoseAsTransforms;
class CSkinRules;
class CTexture;
class IObjectStore;

struct CModelFlags {
  u8 x0_blendMode = 0; /* 2: add color, >6: additive, >4: blend, else opaque */
  u8 x1_matSetIdx = 0;
  EExtendedShader m_extendedShader = EExtendedShader::Lighting;
  bool m_noCull = false;
  bool m_noZWrite = false;
  bool m_depthGreater = false;
  u16 x2_flags = 0;      /* Flags */
  zeus::CColor x4_color; /* Set into kcolor slot specified by material */
  zeus::CColor addColor = zeus::skClear;
  zeus::CAABox mbShadowBox;

  CModelFlags() = default;
  CModelFlags(u8 blendMode, u8 shadIdx, u16 flags, const zeus::CColor& col)
  : x0_blendMode(blendMode), x1_matSetIdx(shadIdx), x2_flags(flags), x4_color(col) {
    /* Blend mode will override this if the surface's original material is opaque */
    m_noZWrite = !(x2_flags & 0x2);
    m_depthGreater = (x2_flags & 0x8);
  }

  /* Flags
      0x1: depth equal
      0x2: depth update
      0x4: render without texture lock
      0x8: depth greater
      0x10: depth non-inclusive
   */

  bool operator==(const CModelFlags& other) const {
    return x0_blendMode == other.x0_blendMode && x1_matSetIdx == other.x1_matSetIdx && x2_flags == other.x2_flags &&
           x4_color == other.x4_color;
  }

  bool operator!=(const CModelFlags& other) const {
    return x0_blendMode != other.x0_blendMode || x1_matSetIdx != other.x1_matSetIdx || x2_flags != other.x2_flags ||
           x4_color != other.x4_color;
  }
};

/* urde addition: doesn't require hacky stashing of
 * pointers within loaded CMDL buffer */
struct CBooSurface {
  DataSpec::DNACMDL::SurfaceHeader_2 m_data;
  size_t selfIdx;
  class CBooModel* m_parent = nullptr;
  CBooSurface* m_next = nullptr;

  zeus::CAABox GetBounds() const {
    if (!m_data.aabbSz)
      return zeus::CAABox(m_data.centroid, m_data.centroid);
    else
      return zeus::CAABox(m_data.aabb[0], m_data.aabb[1]);
  }
};

using MaterialSet = DataSpec::DNAMP1::HMDLMaterialSet;

struct GeometryUniformLayout {
  mutable std::vector<boo::ObjToken<boo::IGraphicsBufferD>> m_sharedBuffer;
  size_t m_geomBufferSize = 0;
  size_t m_skinBankCount = 0;
  size_t m_weightVecCount = 0;

  std::vector<size_t> m_skinOffs;
  std::vector<size_t> m_skinSizes;

  std::vector<size_t> m_uvOffs;
  std::vector<size_t> m_uvSizes;

  GeometryUniformLayout(const CModel* model, const MaterialSet* matSet);
  void Update(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose,
              const MaterialSet* matSet, const boo::ObjToken<boo::IGraphicsBufferD>& buf,
              const CBooModel* parent) const;

  void ReserveSharedBuffers(boo::IGraphicsDataFactory::Context& ctx, int size);
  boo::ObjToken<boo::IGraphicsBufferD> GetSharedBuffer(int idx) const;
};

struct SShader {
  std::unordered_map<CAssetId, TCachedToken<CTexture>> x0_textures;
  std::unordered_map<int, CModelShaders::ShaderPipelines> m_shaders;
  MaterialSet m_matSet;
  std::optional<GeometryUniformLayout> m_geomLayout;
  int m_matSetIdx;
  SShader(int idx) : m_matSetIdx(idx) {
    x0_textures.clear();
    m_shaders.clear();
  }
  void InitializeLayout(const CModel* model) { m_geomLayout.emplace(model, &m_matSet); }
  void UnlockTextures();
  CModelShaders::ShaderPipelines BuildShader(const hecl::HMDLMeta& meta, const MaterialSet::Material& mat);
  void BuildShaders(const hecl::HMDLMeta& meta, std::unordered_map<int, CModelShaders::ShaderPipelines>& shaders);
  void BuildShaders(const hecl::HMDLMeta& meta) { BuildShaders(meta, m_shaders); }
};

class CBooModel {
  friend class CBooRenderer;
  friend class CGameArea;
  friend class CMetroidModelInstance;
  friend class CModel;
  friend class CSkinnedModel;
  friend struct GeometryUniformLayout;

public:
  enum class ESurfaceSelection { UnsortedOnly, SortedOnly, All };

private:
  CBooModel* m_next = nullptr;
  CBooModel* m_prev = nullptr;
  size_t m_uniUpdateCount = 0;
  TToken<CModel> m_modelTok;
  CModel* m_model;
  std::vector<CBooSurface>* x0_surfaces;
  const MaterialSet* x4_matSet;
  const GeometryUniformLayout* m_geomLayout;
  int m_matSetIdx = -1;
  const std::unordered_map<int, CModelShaders::ShaderPipelines>* m_pipelines;
  std::unordered_map<CAssetId, TCachedToken<CTexture>> x1c_textures;
  zeus::CAABox x20_aabb;
  CBooSurface* x38_firstUnsortedSurface = nullptr;
  CBooSurface* x3c_firstSortedSurface = nullptr;
  bool x40_24_texturesLoaded : 1;
  bool x40_25_modelVisible : 1;
  u8 x41_mask;
  u32 x44_areaInstanceIdx = UINT32_MAX;

  struct UVAnimationBuffer {
    static void ProcessAnimation(u8*& bufOut, const MaterialSet::Material::PASS& anim);
    static void PadOutBuffer(u8*& bufStart, u8*& bufOut);
    static void Update(u8*& bufOut, const MaterialSet* matSet, const CModelFlags& flags, const CBooModel* parent);
  };

  CModelShaders::LightingUniform m_lightingData;

  /* urde addition: boo! */
  size_t m_uniformDataSize = 0;
  struct ModelInstance {
    boo::ObjToken<boo::IGraphicsBufferD> m_geomUniformBuffer;
    boo::ObjToken<boo::IGraphicsBufferD> m_uniformBuffer;
    std::vector<std::vector<boo::ObjToken<boo::IShaderDataBinding>>> m_shaderDataBindings;
    boo::ObjToken<boo::IGraphicsBufferD> m_dynamicVbo;

    boo::ObjToken<boo::IGraphicsBuffer> GetBooVBO(const CBooModel& model, boo::IGraphicsDataFactory::Context& ctx);
  };
  std::vector<ModelInstance> m_instances;
  ModelInstance m_ballShadowInstance;

  boo::ObjToken<boo::IGraphicsBufferS> m_staticVbo;
  boo::ObjToken<boo::IGraphicsBufferS> m_staticIbo;

  boo::ObjToken<boo::ITexture> m_lastDrawnShadowMap;
  boo::ObjToken<boo::ITexture> m_lastDrawnOneTexture;
  boo::ObjToken<boo::ITextureCubeR> m_lastDrawnReflectionCube;

  ModelInstance* PushNewModelInstance(int sharedLayoutBuf = -1);
  void DrawAlphaSurfaces(const CModelFlags& flags) const;
  void DrawNormalSurfaces(const CModelFlags& flags) const;
  void DrawSurfaces(const CModelFlags& flags) const;
  void DrawSurface(const CBooSurface& surf, const CModelFlags& flags) const;
  void WarmupDrawSurfaces() const;
  void WarmupDrawSurface(const CBooSurface& surf) const;

  static zeus::CVector3f g_PlayerPosition;
  static float g_ModSeconds;
  static float g_TransformedTime;
  static float g_TransformedTime2;
  static CBooModel* g_LastModelCached;

  static bool g_DummyTextures;
  static bool g_RenderModelBlack;

public:
  ~CBooModel();
  CBooModel(TToken<CModel>& token, CModel* parent, std::vector<CBooSurface>* surfaces, SShader& shader,
            const boo::ObjToken<boo::IGraphicsBufferS>& vbo, const boo::ObjToken<boo::IGraphicsBufferS>& ibo,
            const zeus::CAABox& aabb, u8 renderMask, int numInsts);

  static void MakeTexturesFromMats(const MaterialSet& matSet,
                                   std::unordered_map<CAssetId, TCachedToken<CTexture>>& toksOut,
                                   IObjectStore& store);
  void MakeTexturesFromMats(std::unordered_map<CAssetId, TCachedToken<CTexture>>& toksOut, IObjectStore& store);

  bool IsOpaque() const { return x3c_firstSortedSurface == nullptr; }
  void ActivateLights(const std::vector<CLight>& lights);
  void SetAmbientColor(const zeus::CColor& color) { m_lightingData.ambient = color; }
  void DisableAllLights();
  void RemapMaterialData(SShader& shader);
  void RemapMaterialData(SShader& shader, const std::unordered_map<int, CModelShaders::ShaderPipelines>& pipelines);
  bool TryLockTextures() const;
  void UnlockTextures() const;
  void SyncLoadTextures() const;
  void Touch(int shaderIdx) const;
  void VerifyCurrentShader(int shaderIdx);
  boo::ObjToken<boo::IGraphicsBufferD> UpdateUniformData(const CModelFlags& flags, const CSkinRules* cskr,
                                                         const CPoseAsTransforms* pose, int sharedLayoutBuf = -1) const;
  void DrawAlpha(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const;
  void DrawNormal(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const;
  void Draw(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const;
  void DrawFlat(ESurfaceSelection sel, EExtendedShader extendedIdx) const;

  void LockParent() { m_modelTok.Lock(); }
  void UnlockParent() { m_modelTok.Unlock(); }

  const MaterialSet::Material& GetMaterialByIndex(int idx) const { return x4_matSet->materials.at(idx); }

  void ClearUniformCounter() { m_uniUpdateCount = 0; }
  static void ClearModelUniformCounters();

  static bool g_DrawingOccluders;
  static void SetDrawingOccluders(bool occ) { g_DrawingOccluders = occ; }

  static void SetNewPlayerPositionAndTime(const zeus::CVector3f& pos);

  static zeus::CVector3f g_ReflectViewPos;
  static void KillCachedViewDepState();
  static void EnsureViewDepStateCached(const CBooModel& model, const CBooSurface* surf, zeus::CMatrix4f* mtxsOut,
                                       float& alphaOut);

  static boo::ObjToken<boo::ITexture> g_shadowMap;
  static zeus::CTransform g_shadowTexXf;
  static void EnableShadowMaps(const boo::ObjToken<boo::ITexture>& map, const zeus::CTransform& texXf);
  static void DisableShadowMaps();

  static boo::ObjToken<boo::ITexture> g_disintegrateTexture;
  static void SetDisintegrateTexture(const boo::ObjToken<boo::ITexture>& map) { g_disintegrateTexture = map; }

  static boo::ObjToken<boo::ITextureCubeR> g_reflectionCube;
  static void SetReflectionCube(const boo::ObjToken<boo::ITextureCubeR>& map) { g_reflectionCube = map; }

  static void SetDummyTextures(bool b) { g_DummyTextures = b; }
  static void SetRenderModelBlack(bool b) { g_RenderModelBlack = b; }

  static void Shutdown();

  const zeus::CAABox& GetAABB() const { return x20_aabb; }
};

class CModel {
  friend class CBooModel;
  friend struct GeometryUniformLayout;
  // std::unique_ptr<u8[]> x0_data;
  // u32 x4_dataLen;
  TToken<CModel> m_selfToken; /* DO NOT LOCK! */
  zeus::CAABox m_aabb;
  u32 m_flags;
  std::vector<CBooSurface> x8_surfaces;
  std::vector<SShader> x18_matSets;
  std::unique_ptr<CBooModel> x28_modelInst;
  // CModel* x30_next = nullptr;
  // CModel* x34_prev = nullptr;
  int x38_lastFrame;

  /* urde addition: boo! */
  boo::ObjToken<boo::IGraphicsBufferS> m_staticVbo;
  hecl::HMDLMeta m_hmdlMeta;
  std::unique_ptr<uint8_t[]> m_dynamicVertexData;
  boo::ObjToken<boo::IGraphicsBufferS> m_ibo;

public:
  using MaterialSet = DataSpec::DNAMP1::HMDLMaterialSet;

  CModel(std::unique_ptr<u8[]>&& in, u32 dataLen, IObjectStore* store, CObjectReference* selfRef);
  void DrawSortedParts(const CModelFlags& flags) const;
  void DrawUnsortedParts(const CModelFlags& flags) const;
  void Draw(const CModelFlags& flags) const;
  bool IsLoaded(int shaderIdx) const;
  void Touch(int shaderIdx) { x28_modelInst->Touch(shaderIdx); }

  const zeus::CAABox& GetAABB() const { return m_aabb; }
  CBooModel& GetInstance() { return *x28_modelInst; }
  const CBooModel& GetInstance() const { return *x28_modelInst; }
  std::unique_ptr<CBooModel> MakeNewInstance(int shaderIdx, int subInsts, bool lockParent = true);
  void UpdateLastFrame() const { const_cast<CModel&>(*this).x38_lastFrame = CGraphics::GetFrameCounter(); }

  size_t GetPoolVertexOffset(size_t idx) const;
  zeus::CVector3f GetPoolVertex(size_t idx) const;
  size_t GetPoolNormalOffset(size_t idx) const;
  zeus::CVector3f GetPoolNormal(size_t idx) const;
  void ApplyVerticesCPU(const boo::ObjToken<boo::IGraphicsBufferD>& vertBuf,
                        const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) const;
  void RestoreVerticesCPU(const boo::ObjToken<boo::IGraphicsBufferD>& vertBuf) const;

  void _WarmupShaders();
  static void WarmupShaders(const SObjectTag& cmdlTag);
};

CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag, std::unique_ptr<u8[]>&& in, u32 len,
                               const urde::CVParamTransfer& vparms, CObjectReference* selfRef);

} // namespace urde
<commit_msg>CModel: Implement CModelFlags' operator!= in terms of operator==<commit_after>#pragma once

#include <memory>
#include <optional>
#include <unordered_map>
#include <vector>

#include "DNACommon/CMDL.hpp"
#include "DNAMP1/CMDLMaterials.hpp"
#include "Runtime/CFactoryMgr.hpp"
#include "Runtime/CToken.hpp"
#include "Runtime/RetroTypes.hpp"
#include "Shaders/CModelShaders.hpp"

#include <boo/graphicsdev/IGraphicsDataFactory.hpp>
#include <hecl/HMDLMeta.hpp>
#include <zeus/CAABox.hpp>
#include <zeus/CColor.hpp>

namespace urde {
class CLight;
class CModel;
class CPoseAsTransforms;
class CSkinRules;
class CTexture;
class IObjectStore;

struct CModelFlags {
  u8 x0_blendMode = 0; /* 2: add color, >6: additive, >4: blend, else opaque */
  u8 x1_matSetIdx = 0;
  EExtendedShader m_extendedShader = EExtendedShader::Lighting;
  bool m_noCull = false;
  bool m_noZWrite = false;
  bool m_depthGreater = false;
  u16 x2_flags = 0;      /* Flags */
  zeus::CColor x4_color; /* Set into kcolor slot specified by material */
  zeus::CColor addColor = zeus::skClear;
  zeus::CAABox mbShadowBox;

  CModelFlags() = default;
  CModelFlags(u8 blendMode, u8 shadIdx, u16 flags, const zeus::CColor& col)
  : x0_blendMode(blendMode), x1_matSetIdx(shadIdx), x2_flags(flags), x4_color(col) {
    /* Blend mode will override this if the surface's original material is opaque */
    m_noZWrite = !(x2_flags & 0x2);
    m_depthGreater = (x2_flags & 0x8);
  }

  /* Flags
      0x1: depth equal
      0x2: depth update
      0x4: render without texture lock
      0x8: depth greater
      0x10: depth non-inclusive
   */

  bool operator==(const CModelFlags& other) const {
    return x0_blendMode == other.x0_blendMode && x1_matSetIdx == other.x1_matSetIdx && x2_flags == other.x2_flags &&
           x4_color == other.x4_color;
  }

  bool operator!=(const CModelFlags& other) const { return !operator==(other); }
};

/* urde addition: doesn't require hacky stashing of
 * pointers within loaded CMDL buffer */
struct CBooSurface {
  DataSpec::DNACMDL::SurfaceHeader_2 m_data;
  size_t selfIdx;
  class CBooModel* m_parent = nullptr;
  CBooSurface* m_next = nullptr;

  zeus::CAABox GetBounds() const {
    if (!m_data.aabbSz)
      return zeus::CAABox(m_data.centroid, m_data.centroid);
    else
      return zeus::CAABox(m_data.aabb[0], m_data.aabb[1]);
  }
};

using MaterialSet = DataSpec::DNAMP1::HMDLMaterialSet;

struct GeometryUniformLayout {
  mutable std::vector<boo::ObjToken<boo::IGraphicsBufferD>> m_sharedBuffer;
  size_t m_geomBufferSize = 0;
  size_t m_skinBankCount = 0;
  size_t m_weightVecCount = 0;

  std::vector<size_t> m_skinOffs;
  std::vector<size_t> m_skinSizes;

  std::vector<size_t> m_uvOffs;
  std::vector<size_t> m_uvSizes;

  GeometryUniformLayout(const CModel* model, const MaterialSet* matSet);
  void Update(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose,
              const MaterialSet* matSet, const boo::ObjToken<boo::IGraphicsBufferD>& buf,
              const CBooModel* parent) const;

  void ReserveSharedBuffers(boo::IGraphicsDataFactory::Context& ctx, int size);
  boo::ObjToken<boo::IGraphicsBufferD> GetSharedBuffer(int idx) const;
};

struct SShader {
  std::unordered_map<CAssetId, TCachedToken<CTexture>> x0_textures;
  std::unordered_map<int, CModelShaders::ShaderPipelines> m_shaders;
  MaterialSet m_matSet;
  std::optional<GeometryUniformLayout> m_geomLayout;
  int m_matSetIdx;
  SShader(int idx) : m_matSetIdx(idx) {
    x0_textures.clear();
    m_shaders.clear();
  }
  void InitializeLayout(const CModel* model) { m_geomLayout.emplace(model, &m_matSet); }
  void UnlockTextures();
  CModelShaders::ShaderPipelines BuildShader(const hecl::HMDLMeta& meta, const MaterialSet::Material& mat);
  void BuildShaders(const hecl::HMDLMeta& meta, std::unordered_map<int, CModelShaders::ShaderPipelines>& shaders);
  void BuildShaders(const hecl::HMDLMeta& meta) { BuildShaders(meta, m_shaders); }
};

class CBooModel {
  friend class CBooRenderer;
  friend class CGameArea;
  friend class CMetroidModelInstance;
  friend class CModel;
  friend class CSkinnedModel;
  friend struct GeometryUniformLayout;

public:
  enum class ESurfaceSelection { UnsortedOnly, SortedOnly, All };

private:
  CBooModel* m_next = nullptr;
  CBooModel* m_prev = nullptr;
  size_t m_uniUpdateCount = 0;
  TToken<CModel> m_modelTok;
  CModel* m_model;
  std::vector<CBooSurface>* x0_surfaces;
  const MaterialSet* x4_matSet;
  const GeometryUniformLayout* m_geomLayout;
  int m_matSetIdx = -1;
  const std::unordered_map<int, CModelShaders::ShaderPipelines>* m_pipelines;
  std::unordered_map<CAssetId, TCachedToken<CTexture>> x1c_textures;
  zeus::CAABox x20_aabb;
  CBooSurface* x38_firstUnsortedSurface = nullptr;
  CBooSurface* x3c_firstSortedSurface = nullptr;
  bool x40_24_texturesLoaded : 1;
  bool x40_25_modelVisible : 1;
  u8 x41_mask;
  u32 x44_areaInstanceIdx = UINT32_MAX;

  struct UVAnimationBuffer {
    static void ProcessAnimation(u8*& bufOut, const MaterialSet::Material::PASS& anim);
    static void PadOutBuffer(u8*& bufStart, u8*& bufOut);
    static void Update(u8*& bufOut, const MaterialSet* matSet, const CModelFlags& flags, const CBooModel* parent);
  };

  CModelShaders::LightingUniform m_lightingData;

  /* urde addition: boo! */
  size_t m_uniformDataSize = 0;
  struct ModelInstance {
    boo::ObjToken<boo::IGraphicsBufferD> m_geomUniformBuffer;
    boo::ObjToken<boo::IGraphicsBufferD> m_uniformBuffer;
    std::vector<std::vector<boo::ObjToken<boo::IShaderDataBinding>>> m_shaderDataBindings;
    boo::ObjToken<boo::IGraphicsBufferD> m_dynamicVbo;

    boo::ObjToken<boo::IGraphicsBuffer> GetBooVBO(const CBooModel& model, boo::IGraphicsDataFactory::Context& ctx);
  };
  std::vector<ModelInstance> m_instances;
  ModelInstance m_ballShadowInstance;

  boo::ObjToken<boo::IGraphicsBufferS> m_staticVbo;
  boo::ObjToken<boo::IGraphicsBufferS> m_staticIbo;

  boo::ObjToken<boo::ITexture> m_lastDrawnShadowMap;
  boo::ObjToken<boo::ITexture> m_lastDrawnOneTexture;
  boo::ObjToken<boo::ITextureCubeR> m_lastDrawnReflectionCube;

  ModelInstance* PushNewModelInstance(int sharedLayoutBuf = -1);
  void DrawAlphaSurfaces(const CModelFlags& flags) const;
  void DrawNormalSurfaces(const CModelFlags& flags) const;
  void DrawSurfaces(const CModelFlags& flags) const;
  void DrawSurface(const CBooSurface& surf, const CModelFlags& flags) const;
  void WarmupDrawSurfaces() const;
  void WarmupDrawSurface(const CBooSurface& surf) const;

  static zeus::CVector3f g_PlayerPosition;
  static float g_ModSeconds;
  static float g_TransformedTime;
  static float g_TransformedTime2;
  static CBooModel* g_LastModelCached;

  static bool g_DummyTextures;
  static bool g_RenderModelBlack;

public:
  ~CBooModel();
  CBooModel(TToken<CModel>& token, CModel* parent, std::vector<CBooSurface>* surfaces, SShader& shader,
            const boo::ObjToken<boo::IGraphicsBufferS>& vbo, const boo::ObjToken<boo::IGraphicsBufferS>& ibo,
            const zeus::CAABox& aabb, u8 renderMask, int numInsts);

  static void MakeTexturesFromMats(const MaterialSet& matSet,
                                   std::unordered_map<CAssetId, TCachedToken<CTexture>>& toksOut,
                                   IObjectStore& store);
  void MakeTexturesFromMats(std::unordered_map<CAssetId, TCachedToken<CTexture>>& toksOut, IObjectStore& store);

  bool IsOpaque() const { return x3c_firstSortedSurface == nullptr; }
  void ActivateLights(const std::vector<CLight>& lights);
  void SetAmbientColor(const zeus::CColor& color) { m_lightingData.ambient = color; }
  void DisableAllLights();
  void RemapMaterialData(SShader& shader);
  void RemapMaterialData(SShader& shader, const std::unordered_map<int, CModelShaders::ShaderPipelines>& pipelines);
  bool TryLockTextures() const;
  void UnlockTextures() const;
  void SyncLoadTextures() const;
  void Touch(int shaderIdx) const;
  void VerifyCurrentShader(int shaderIdx);
  boo::ObjToken<boo::IGraphicsBufferD> UpdateUniformData(const CModelFlags& flags, const CSkinRules* cskr,
                                                         const CPoseAsTransforms* pose, int sharedLayoutBuf = -1) const;
  void DrawAlpha(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const;
  void DrawNormal(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const;
  void Draw(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const;
  void DrawFlat(ESurfaceSelection sel, EExtendedShader extendedIdx) const;

  void LockParent() { m_modelTok.Lock(); }
  void UnlockParent() { m_modelTok.Unlock(); }

  const MaterialSet::Material& GetMaterialByIndex(int idx) const { return x4_matSet->materials.at(idx); }

  void ClearUniformCounter() { m_uniUpdateCount = 0; }
  static void ClearModelUniformCounters();

  static bool g_DrawingOccluders;
  static void SetDrawingOccluders(bool occ) { g_DrawingOccluders = occ; }

  static void SetNewPlayerPositionAndTime(const zeus::CVector3f& pos);

  static zeus::CVector3f g_ReflectViewPos;
  static void KillCachedViewDepState();
  static void EnsureViewDepStateCached(const CBooModel& model, const CBooSurface* surf, zeus::CMatrix4f* mtxsOut,
                                       float& alphaOut);

  static boo::ObjToken<boo::ITexture> g_shadowMap;
  static zeus::CTransform g_shadowTexXf;
  static void EnableShadowMaps(const boo::ObjToken<boo::ITexture>& map, const zeus::CTransform& texXf);
  static void DisableShadowMaps();

  static boo::ObjToken<boo::ITexture> g_disintegrateTexture;
  static void SetDisintegrateTexture(const boo::ObjToken<boo::ITexture>& map) { g_disintegrateTexture = map; }

  static boo::ObjToken<boo::ITextureCubeR> g_reflectionCube;
  static void SetReflectionCube(const boo::ObjToken<boo::ITextureCubeR>& map) { g_reflectionCube = map; }

  static void SetDummyTextures(bool b) { g_DummyTextures = b; }
  static void SetRenderModelBlack(bool b) { g_RenderModelBlack = b; }

  static void Shutdown();

  const zeus::CAABox& GetAABB() const { return x20_aabb; }
};

class CModel {
  friend class CBooModel;
  friend struct GeometryUniformLayout;
  // std::unique_ptr<u8[]> x0_data;
  // u32 x4_dataLen;
  TToken<CModel> m_selfToken; /* DO NOT LOCK! */
  zeus::CAABox m_aabb;
  u32 m_flags;
  std::vector<CBooSurface> x8_surfaces;
  std::vector<SShader> x18_matSets;
  std::unique_ptr<CBooModel> x28_modelInst;
  // CModel* x30_next = nullptr;
  // CModel* x34_prev = nullptr;
  int x38_lastFrame;

  /* urde addition: boo! */
  boo::ObjToken<boo::IGraphicsBufferS> m_staticVbo;
  hecl::HMDLMeta m_hmdlMeta;
  std::unique_ptr<uint8_t[]> m_dynamicVertexData;
  boo::ObjToken<boo::IGraphicsBufferS> m_ibo;

public:
  using MaterialSet = DataSpec::DNAMP1::HMDLMaterialSet;

  CModel(std::unique_ptr<u8[]>&& in, u32 dataLen, IObjectStore* store, CObjectReference* selfRef);
  void DrawSortedParts(const CModelFlags& flags) const;
  void DrawUnsortedParts(const CModelFlags& flags) const;
  void Draw(const CModelFlags& flags) const;
  bool IsLoaded(int shaderIdx) const;
  void Touch(int shaderIdx) { x28_modelInst->Touch(shaderIdx); }

  const zeus::CAABox& GetAABB() const { return m_aabb; }
  CBooModel& GetInstance() { return *x28_modelInst; }
  const CBooModel& GetInstance() const { return *x28_modelInst; }
  std::unique_ptr<CBooModel> MakeNewInstance(int shaderIdx, int subInsts, bool lockParent = true);
  void UpdateLastFrame() const { const_cast<CModel&>(*this).x38_lastFrame = CGraphics::GetFrameCounter(); }

  size_t GetPoolVertexOffset(size_t idx) const;
  zeus::CVector3f GetPoolVertex(size_t idx) const;
  size_t GetPoolNormalOffset(size_t idx) const;
  zeus::CVector3f GetPoolNormal(size_t idx) const;
  void ApplyVerticesCPU(const boo::ObjToken<boo::IGraphicsBufferD>& vertBuf,
                        const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) const;
  void RestoreVerticesCPU(const boo::ObjToken<boo::IGraphicsBufferD>& vertBuf) const;

  void _WarmupShaders();
  static void WarmupShaders(const SObjectTag& cmdlTag);
};

CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag, std::unique_ptr<u8[]>&& in, u32 len,
                               const urde::CVParamTransfer& vparms, CObjectReference* selfRef);

} // namespace urde
<|endoftext|>


<commit_before>/*
 *  illarionserver - server for the game Illarion
 *  Copyright 2011 Illarion e.V.
 *
 *  This file is part of illarionserver.
 *
 *  illarionserver is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  illarionserver is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with illarionserver.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "LuaQuestScript.hpp"
#include "Character.hpp"
#include "character_ptr.hpp"

LuaQuestScript::LuaQuestScript(const std::string &filename, TYPE_OF_QUEST_ID quest) throw(ScriptException)
    : LuaScript(filename), quest(quest) {
}

LuaQuestScript::~LuaQuestScript() throw() {}

std::string LuaQuestScript::title(Character *user) {
    character_ptr fuse_user(user);
    return callEntrypoint<std::string>("QuestTitle", fuse_user);
}

std::string LuaQuestScript::description(Character *user, TYPE_OF_QUESTSTATUS status) {
    character_ptr fuse_user(user);
    return callEntrypoint<std::string>("QuestDescription", fuse_user, status);
}

QuestAvailability LuaQuestScript::available(Character *user, TYPE_OF_QUESTSTATUS status) {
    character_ptr fuse_user(user);
    return callEntrypoint<QuestAvailability>("QuestAvailability", fuse_user, status);
}

position LuaQuestScript::start() {
    using namespace luabind;
    auto startPosition = callEntrypoint<object>("QuestStart");

    try {
        return getPosition(startPosition);
    } catch (std::logic_error &e) {
        std::stringstream error;
        error << "No valid QuestStart entrypoint in quest " << quest << ".";
        writeDebugMsg(error.str());
        throw;
    }
}

void LuaQuestScript::targets(Character *user, TYPE_OF_QUESTSTATUS status, std::vector<position> &targets) {
    using namespace luabind;
    targets.clear();
    character_ptr fuse_user(user);
    auto luaTargets = callEntrypoint<object>("QuestTargets", fuse_user, status);

    if (!luaTargets.is_valid()) {
        std::stringstream error;
        error << "No valid QuestTarget entrypoint in quest " << quest << ".";
        writeDebugMsg(error.str());
        return;
    }

    try {
        targets.push_back(getPosition(luaTargets));
        return;
    } catch (std::logic_error &e) {
    }

    auto mapType = type(luaTargets);

    if (mapType == LUA_TTABLE) {
        for (iterator it(luaTargets), end; it != end; ++it) {
            try {
                targets.push_back(getPosition(*it));
            } catch (std::logic_error &e) {
                std::stringstream error;
                error << "Usage of invalid target table entry in quest " << quest;
                error << " for status " << status << ". A target table entry ";
                error << "must be either a position or a table of three coordinates.";
                writeDebugMsg(error.str());
            }
        }
    } else if (mapType == LUA_TNIL) {
        // no targets to add
    } else {
        std::stringstream error;
        error << "Usage of invalid quest target type in quest " << quest;
        error << " for status " << status << ". You must return a table of positions and/or";
        error << " coordinates, a position, a table of three coordinates or nil in QuestTargets!";
        writeDebugMsg(error.str());
    }
}

TYPE_OF_QUESTSTATUS LuaQuestScript::finalStatus() {
    return callEntrypoint<TYPE_OF_QUESTSTATUS>("QuestFinalStatus");
}

position LuaQuestScript::getPosition(const luabind::object &potentialPosition) {
    using namespace luabind;

    if (!potentialPosition.is_valid()) {
        throw std::logic_error("no position found");
    }

    try {
        return object_cast<position>(potentialPosition);
    } catch (cast_failed &e) {
    }

    auto positionType = type(potentialPosition);

    if (positionType == LUA_TTABLE) {
        try {
            int16_t x = object_cast<int16_t>(potentialPosition[1]);
            int16_t y = object_cast<int16_t>(potentialPosition[2]);
            int16_t z = object_cast<int16_t>(potentialPosition[3]);
            return position(x, y, z);
        } catch (cast_failed &e) {
        }
    }

    throw std::logic_error("no position found");
}
<commit_msg>Fix default for missing QuestAvailability entry point<commit_after>/*
 *  illarionserver - server for the game Illarion
 *  Copyright 2011 Illarion e.V.
 *
 *  This file is part of illarionserver.
 *
 *  illarionserver is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  illarionserver is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with illarionserver.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "LuaQuestScript.hpp"
#include "Character.hpp"
#include "character_ptr.hpp"

LuaQuestScript::LuaQuestScript(const std::string &filename, TYPE_OF_QUEST_ID quest) throw(ScriptException)
    : LuaScript(filename), quest(quest) {
}

LuaQuestScript::~LuaQuestScript() throw() {}

std::string LuaQuestScript::title(Character *user) {
    character_ptr fuse_user(user);
    return callEntrypoint<std::string>("QuestTitle", fuse_user);
}

std::string LuaQuestScript::description(Character *user, TYPE_OF_QUESTSTATUS status) {
    character_ptr fuse_user(user);
    return callEntrypoint<std::string>("QuestDescription", fuse_user, status);
}

QuestAvailability LuaQuestScript::available(Character *user, TYPE_OF_QUESTSTATUS status) {
    if (!existsEntrypoint("QuestAvailability")) {
        return questDefaultAvailable;
    }

    character_ptr fuse_user(user);
    return callEntrypoint<QuestAvailability>("QuestAvailability", fuse_user, status);
}

position LuaQuestScript::start() {
    using namespace luabind;
    auto startPosition = callEntrypoint<object>("QuestStart");

    try {
        return getPosition(startPosition);
    } catch (std::logic_error &e) {
        std::stringstream error;
        error << "No valid QuestStart entrypoint in quest " << quest << ".";
        writeDebugMsg(error.str());
        throw;
    }
}

void LuaQuestScript::targets(Character *user, TYPE_OF_QUESTSTATUS status, std::vector<position> &targets) {
    using namespace luabind;
    targets.clear();
    character_ptr fuse_user(user);
    auto luaTargets = callEntrypoint<object>("QuestTargets", fuse_user, status);

    if (!luaTargets.is_valid()) {
        std::stringstream error;
        error << "No valid QuestTarget entrypoint in quest " << quest << ".";
        writeDebugMsg(error.str());
        return;
    }

    try {
        targets.push_back(getPosition(luaTargets));
        return;
    } catch (std::logic_error &e) {
    }

    auto mapType = type(luaTargets);

    if (mapType == LUA_TTABLE) {
        for (iterator it(luaTargets), end; it != end; ++it) {
            try {
                targets.push_back(getPosition(*it));
            } catch (std::logic_error &e) {
                std::stringstream error;
                error << "Usage of invalid target table entry in quest " << quest;
                error << " for status " << status << ". A target table entry ";
                error << "must be either a position or a table of three coordinates.";
                writeDebugMsg(error.str());
            }
        }
    } else if (mapType == LUA_TNIL) {
        // no targets to add
    } else {
        std::stringstream error;
        error << "Usage of invalid quest target type in quest " << quest;
        error << " for status " << status << ". You must return a table of positions and/or";
        error << " coordinates, a position, a table of three coordinates or nil in QuestTargets!";
        writeDebugMsg(error.str());
    }
}

TYPE_OF_QUESTSTATUS LuaQuestScript::finalStatus() {
    return callEntrypoint<TYPE_OF_QUESTSTATUS>("QuestFinalStatus");
}

position LuaQuestScript::getPosition(const luabind::object &potentialPosition) {
    using namespace luabind;

    if (!potentialPosition.is_valid()) {
        throw std::logic_error("no position found");
    }

    try {
        return object_cast<position>(potentialPosition);
    } catch (cast_failed &e) {
    }

    auto positionType = type(potentialPosition);

    if (positionType == LUA_TTABLE) {
        try {
            int16_t x = object_cast<int16_t>(potentialPosition[1]);
            int16_t y = object_cast<int16_t>(potentialPosition[2]);
            int16_t z = object_cast<int16_t>(potentialPosition[3]);
            return position(x, y, z);
        } catch (cast_failed &e) {
        }
    }

    throw std::logic_error("no position found");
}
<|endoftext|>


<commit_before>/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

extern "C" {
#include <signal.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/poll.h>
}

#include <remotepluginprocess.h>

using namespace RemotePluginProcessNS;

RemotePluginProcess *process = NULL;

int main(int argc, char *argv[])
{
    TRACE();

#ifndef NO_SIGNON_USER
    if (!::getuid()) {
        BLAME() << argv[0] << " cannot be started with root priviledges!!!";
        exit(2);
    }
#endif

    QCoreApplication app(argc, argv);

    if (argc < 2) {
        TRACE() << "Type of plugin is not specified";
        exit(1);
    }

    QString type = app.arguments().at(1); TRACE() << type;

    fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL, 0) | O_NONBLOCK);

    process = RemotePluginProcess::createRemotePluginProcess(type, &app);

    if (!process)
        return 1;

    fprintf(stdout, "process started");
    fflush(stdout);

    QObject::connect(process, SIGNAL(processStopped()), &app, SLOT(quit()));
    return app.exec();
}
<commit_msg>RemotePluginProcess: use syslog for debugging<commit_after>/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

extern "C" {
#include <signal.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <syslog.h>
}

#include "remotepluginprocess.h"

#include <QDebug>

using namespace RemotePluginProcessNS;

RemotePluginProcess *process = NULL;

static void messageHandler(QtMsgType type, const char *msg)
{
    int priority;
    switch (type) {
        case QtWarningMsg: priority = LOG_WARNING; break;
        case QtCriticalMsg: priority = LOG_CRIT; break;
        case QtFatalMsg: priority = LOG_EMERG; break;
        case QtDebugMsg:
                         /* fall through */
        default: priority = LOG_INFO; break;
    }

    syslog(priority, msg);
}

int main(int argc, char *argv[])
{
    qInstallMsgHandler(messageHandler);

    TRACE();

#ifndef NO_SIGNON_USER
    if (!::getuid()) {
        BLAME() << argv[0] << " cannot be started with root priviledges!!!";
        exit(2);
    }
#endif

    QCoreApplication app(argc, argv);

    if (argc < 2) {
        TRACE() << "Type of plugin is not specified";
        exit(1);
    }

    QString type = app.arguments().at(1); TRACE() << type;

    fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL, 0) | O_NONBLOCK);

    process = RemotePluginProcess::createRemotePluginProcess(type, &app);

    if (!process)
        return 1;

    fprintf(stdout, "process started");
    fflush(stdout);

    QObject::connect(process, SIGNAL(processStopped()), &app, SLOT(quit()));
    return app.exec();
}
<|endoftext|>


<commit_before><commit_msg>cppcheck: Possible inefficient checking for emptiness<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Love Park Robotics, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distribted on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "o3d3xx_framegrabber/frame_grabber.h"
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <cstdlib>
#include <exception>
#include <stdexcept>
#include <functional>
#include <iomanip>
#include <mutex>
#include <sstream>
#include <string>
#include <system_error>
#include <boost/asio.hpp>
#include <boost/system/system_error.hpp>
#include <glog/logging.h>
#include "o3d3xx_camera/camera.hpp"
#include "o3d3xx_camera/err.h"
#include "o3d3xx_camera/device_config.h"
#include "o3d3xx_camera/app_config.h"
#include "o3d3xx_framegrabber/byte_buffer.hpp"
#include "o3d3xx_framegrabber/pcic_schema.h"

// <Ticket><Length>CR+LF (16 bytes)
const std::size_t o3d3xx::TICKET_ID_SZ = 16;
const std::string o3d3xx::TICKET_image = "0000";
const std::string o3d3xx::TICKET_c = "1000";
const std::string o3d3xx::TICKET_t = "1001";

o3d3xx::FrameGrabber::FrameGrabber(o3d3xx::Camera::Ptr cam,
                                   std::uint16_t mask)
  : cam_(cam),
    io_service_(),
    sock_(io_service_),
    pcic_ready_(false),
    mask_(mask)
{
  this->SetSchemaBuffer(this->mask_);
  this->SetTriggerBuffer();

  try
    {
      this->cam_ip_ = this->cam_->GetIP();
      this->cam_port_ = std::stoi(this->cam_->GetParameter("PcicTcpPort"));
    }
  catch (const o3d3xx::error_t& ex)
    {
      LOG(ERROR) << "Could not get IP/Port of the camera: "
                 << ex.what();
      // NOTE: GetIP() won't throw, so, the problem must be getting the PCIC
      // port. Here we assume the default. Former behavior was to throw!
      LOG(WARNING) << "Assuming default PCIC port!";
      this->cam_port_ = o3d3xx::DEFAULT_PCIC_PORT;
    }

  LOG(INFO) << "Camera connection info: ip=" << this->cam_ip_
            << ", port=" << this->cam_port_;

  this->endpoint_ =
    boost::asio::ip::tcp::endpoint(
      boost::asio::ip::address::from_string(this->cam_ip_), this->cam_port_);

  this->thread_ =
    std::unique_ptr<std::thread>(
      new std::thread(std::bind(&o3d3xx::FrameGrabber::Run, this)));
}

o3d3xx::FrameGrabber::~FrameGrabber()
{
  DLOG(INFO) << "FrameGrabber dtor running...";

  if (this->thread_ && this->thread_->joinable())
    {
      // NOTE: If Stop() was already called, that is fine
      // because the ASIO event loop is already done so the posted exception
      // will never get emitted.
      this->Stop();
      this->thread_->join();
    }

  DLOG(INFO) << "FrameGrabber done.";
}

void
o3d3xx::FrameGrabber::SetSchemaBuffer(std::uint16_t mask)
{
  std::string schema = o3d3xx::make_pcic_schema(mask);
  int c_len = 4 + 1 + 9 + schema.size() + 2;
  std::ostringstream str;
  str << o3d3xx::TICKET_c
      << 'L' << std::setfill('0') << std::setw(9) << c_len
      << '\r' << '\n'
      << o3d3xx::TICKET_c << 'c'
      << std::setfill('0') << std::setw(9)
      << schema.size()
      << schema
      << '\r' << '\n';

  std::string c_command = str.str();
  this->schema_buffer_.assign(c_command.begin(), c_command.end());
  DLOG(INFO) << "c_command: " << c_command;
}

void
o3d3xx::FrameGrabber::SetTriggerBuffer()
{
  int t_len = 4 + 1 + 2;
  std::ostringstream str;
  str << o3d3xx::TICKET_t
      << 'L' << std::setfill('0') << std::setw(9) << t_len
      << '\r' << '\n'
      << o3d3xx::TICKET_t << 't' << '\r' << '\n';

  std::string t_command = str.str();
  this->trigger_buffer_.assign(t_command.begin(), t_command.end());
}

void
o3d3xx::FrameGrabber::SWTrigger()
{
  int i = 0;
  while (! this->pcic_ready_.load())
    {
      std::this_thread::sleep_for(std::chrono::milliseconds(1));
      i++;

      if (i > 2000)
        {
          LOG(WARNING) << "pcic_ready_ flag not set!";
          return;
        }
    }

  this->io_service_.post(
    [=]()
    {
      boost::asio::async_write(
        this->sock_,
        boost::asio::buffer(this->trigger_buffer_.data(),
                            this->trigger_buffer_.size()),
        [=] (const boost::system::error_code& ec,
             std::size_t bytes_transferred)
        {
          if (ec) { throw o3d3xx::error_t(ec.value()); }
        });
    });
}

void
o3d3xx::FrameGrabber::Stop()
{
  this->io_service_.post([]() {
      throw o3d3xx::error_t(O3D3XX_THREAD_INTERRUPTED); });
}

bool
o3d3xx::FrameGrabber::WaitForFrame(o3d3xx::ByteBuffer* buff,
                                   long timeout_millis,
                                   bool copy_buff,
                                   bool organize)
{
  // mutex will unlock in `unique_lock' dtor if not explicitly unlocked prior
  std::unique_lock<std::mutex> lock(this->front_buffer_mutex_);

  try
    {
      if (timeout_millis <= 0)
        {
          this->front_buffer_cv_.wait(lock);
        }
      else
        {
          if (this->front_buffer_cv_.wait_for(
               lock, std::chrono::milliseconds(timeout_millis)) ==
              std::cv_status::timeout)
            {
              LOG(WARNING) << "Timeout waiting for image buffer from camera";
              return false;
            }
        }
    }
  catch (const std::system_error& ex)
    {
      LOG(WARNING) << "WaitForFrame: " << ex.what();
      return false;
    }

  DLOG(INFO) << "Client fetching new image data";
  buff->SetBytes(this->front_buffer_, copy_buff);
  lock.unlock();

  if (organize)
    {
      buff->Organize();
    }

  return true;
}

void
o3d3xx::FrameGrabber::ImageHandler(const boost::system::error_code& ec,
                                   std::size_t bytes_transferred,
                                   std::size_t bytes_read)
{
  if (ec) { throw o3d3xx::error_t(ec.value()); }

  bytes_read += bytes_transferred;

  if (bytes_read != this->back_buffer_.size())
    {
      this->sock_.async_read_some(
        boost::asio::buffer(&this->back_buffer_[bytes_read],
                            this->back_buffer_.size() - bytes_read),
        std::bind(&o3d3xx::FrameGrabber::ImageHandler, this,
                  std::placeholders::_1, std::placeholders::_2, bytes_read));
      return;
    }

  if (o3d3xx::verify_image_buffer(this->back_buffer_))
    {
      // Move data to front buffer in O(1)
      this->front_buffer_mutex_.lock();
      this->back_buffer_.swap(this->front_buffer_);
      this->front_buffer_mutex_.unlock();

      // notify waiting clients
      this->front_buffer_cv_.notify_all();
    }
  else
    {
      LOG(WARNING) << "Bad image!";
    }

  this->ticket_buffer_.clear();
  this->ticket_buffer_.resize(o3d3xx::TICKET_ID_SZ);
  this->sock_.async_read_some(
    boost::asio::buffer(this->ticket_buffer_.data(),
                        o3d3xx::TICKET_ID_SZ),
    std::bind(&o3d3xx::FrameGrabber::TicketHandler, this,
              std::placeholders::_1, std::placeholders::_2, 0));
}

void
o3d3xx::FrameGrabber::TicketHandler(const boost::system::error_code& ec,
                                    std::size_t bytes_transferred,
                                    std::size_t bytes_read)
{
  if (ec) { throw o3d3xx::error_t(ec.value()); }

  bytes_read += bytes_transferred;

  if (bytes_read < o3d3xx::TICKET_ID_SZ)
    {
      bytes_read +=
        boost::asio::read(
          this->sock_,
          boost::asio::buffer(&this->ticket_buffer_[bytes_read],
                              o3d3xx::TICKET_ID_SZ - bytes_read));

      if (bytes_read != o3d3xx::TICKET_ID_SZ)
        {
          LOG(ERROR) << "Timeout reading ticket!";
          throw o3d3xx::error_t(O3D3XX_IO_ERROR);
        }
    }

  std::string ticket;
  ticket.assign(this->ticket_buffer_.begin(),
                this->ticket_buffer_.begin() + 4);

  std::string payload_sz_str;
  payload_sz_str.assign(this->ticket_buffer_.begin()+5,
                        this->ticket_buffer_.begin()+14);
  int payload_sz = std::stoi(payload_sz_str);
  int ticket_sz = o3d3xx::TICKET_ID_SZ;

  if (ticket != o3d3xx::TICKET_image)
    {
      this->ticket_buffer_.resize(ticket_sz + payload_sz);

      bytes_read +=
        boost::asio::read(
          this->sock_,
          boost::asio::buffer(&this->ticket_buffer_[bytes_read],
                              (ticket_sz + payload_sz) - bytes_read));

      if (bytes_read != (ticket_sz + payload_sz))
        {
          LOG(ERROR) << "Timeout reading whole response!";
          LOG(ERROR) << "Got " << bytes_read << " bytes of "
                     << ticket_sz << " bytes expected";

          throw o3d3xx::error_t(O3D3XX_IO_ERROR);
        }
    }

  std::string ticket_str;
  ticket_str.assign(this->ticket_buffer_.begin(),
                    this->ticket_buffer_.end());
  DLOG(INFO) << "Ticket Full: '" << ticket_str << "'";

  if (ticket == o3d3xx::TICKET_image)
    {
      if (o3d3xx::verify_ticket_buffer(this->ticket_buffer_))
        {
          this->back_buffer_.resize(
            o3d3xx::get_image_buffer_size(this->ticket_buffer_));

          this->sock_.async_read_some(
            boost::asio::buffer(this->back_buffer_.data(),
                                this->back_buffer_.size()),
            std::bind(&o3d3xx::FrameGrabber::ImageHandler, this,
                      std::placeholders::_1, std::placeholders::_2, 0));
          return;
        }
      else
        {
          LOG(ERROR) << "Bad image ticket: " << ticket_str;
          throw(o3d3xx::error_t(O3D3XX_PCIC_BAD_REPLY));
        }
    }
  else if ((ticket == o3d3xx::TICKET_c) ||
           (ticket == o3d3xx::TICKET_t))
    {
      if (this->ticket_buffer_.at(20) != '*')
        {
          LOG(ERROR) << "Bad ticket: " << ticket_str;

          if ((ticket == o3d3xx::TICKET_t) &&
              (this->ticket_buffer_.at(20) == '!'))
            {
              LOG(WARNING) << "Are you software triggering in free run mode?";
            }
          else
            {
              throw(o3d3xx::error_t(O3D3XX_PCIC_BAD_REPLY));
            }
        }

      this->ticket_buffer_.clear();
      this->ticket_buffer_.resize(o3d3xx::TICKET_ID_SZ);
      this->sock_.async_read_some(
        boost::asio::buffer(this->ticket_buffer_.data(),
                            o3d3xx::TICKET_ID_SZ),
        std::bind(&o3d3xx::FrameGrabber::TicketHandler, this,
                  std::placeholders::_1, std::placeholders::_2, 0));

      return;
    }
  else
    {
      LOG(WARNING) << "Unexpected ticket: " << ticket;
      LOG(WARNING) << "Ticket Full: '" << ticket_str << "'";
      //throw(std::logic_error("Unexpected ticket type: " + ticket));

      this->ticket_buffer_.clear();
      this->ticket_buffer_.resize(o3d3xx::TICKET_ID_SZ);
      this->sock_.async_read_some(
        boost::asio::buffer(this->ticket_buffer_.data(),
                            o3d3xx::TICKET_ID_SZ),
        std::bind(&o3d3xx::FrameGrabber::TicketHandler, this,
                  std::placeholders::_1, std::placeholders::_2, 0));

      return;
    }
}

void
o3d3xx::FrameGrabber::Run()
{
  boost::asio::io_service::work work(this->io_service_);

  auto result_schema_write_handler =
    [&, this]
    (const boost::system::error_code& ec, std::size_t bytes_transferred)
    {
      if (ec) { throw o3d3xx::error_t(ec.value()); }
      this->ticket_buffer_.clear();
      this->ticket_buffer_.resize(o3d3xx::TICKET_ID_SZ);

      this->sock_.async_read_some(
        boost::asio::buffer(this->ticket_buffer_.data(),
                            o3d3xx::TICKET_ID_SZ),
        std::bind(&o3d3xx::FrameGrabber::TicketHandler,
                  this, std::placeholders::_1,
                  std::placeholders::_2, 0));

      this->pcic_ready_.store(true);
    };

  //
  // Establish TCP connection to sensor and
  // set PCIC schema for this session
  //
  try
    {
      this->sock_.async_connect(
        this->endpoint_,
        [&, this] (const boost::system::error_code& ec)
        {
          if (ec) { throw o3d3xx::error_t(ec.value()); }
          boost::asio::async_write(
            this->sock_,
            boost::asio::buffer(this->schema_buffer_.data(),
                                this->schema_buffer_.size()),
            result_schema_write_handler);
        });

      this->io_service_.run();
    }
  catch (const std::exception& ex)
    {
      LOG(WARNING) << "Exception: " << ex.what();
    }

  LOG(INFO) << "Framegrabber thread done.";
}
<commit_msg>Handle spurious wakeups in WaitForFrame<commit_after>/*
 * Copyright (C) 2014 Love Park Robotics, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distribted on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "o3d3xx_framegrabber/frame_grabber.h"
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <cstdlib>
#include <exception>
#include <stdexcept>
#include <functional>
#include <iomanip>
#include <mutex>
#include <sstream>
#include <string>
#include <system_error>
#include <boost/asio.hpp>
#include <boost/system/system_error.hpp>
#include <glog/logging.h>
#include "o3d3xx_camera/camera.hpp"
#include "o3d3xx_camera/err.h"
#include "o3d3xx_camera/device_config.h"
#include "o3d3xx_camera/app_config.h"
#include "o3d3xx_framegrabber/byte_buffer.hpp"
#include "o3d3xx_framegrabber/pcic_schema.h"

// <Ticket><Length>CR+LF (16 bytes)
const std::size_t o3d3xx::TICKET_ID_SZ = 16;
const std::string o3d3xx::TICKET_image = "0000";
const std::string o3d3xx::TICKET_c = "1000";
const std::string o3d3xx::TICKET_t = "1001";

o3d3xx::FrameGrabber::FrameGrabber(o3d3xx::Camera::Ptr cam,
                                   std::uint16_t mask)
  : cam_(cam),
    io_service_(),
    sock_(io_service_),
    pcic_ready_(false),
    mask_(mask)
{
  this->SetSchemaBuffer(this->mask_);
  this->SetTriggerBuffer();

  try
    {
      this->cam_ip_ = this->cam_->GetIP();
      this->cam_port_ = std::stoi(this->cam_->GetParameter("PcicTcpPort"));
    }
  catch (const o3d3xx::error_t& ex)
    {
      LOG(ERROR) << "Could not get IP/Port of the camera: "
                 << ex.what();
      // NOTE: GetIP() won't throw, so, the problem must be getting the PCIC
      // port. Here we assume the default. Former behavior was to throw!
      LOG(WARNING) << "Assuming default PCIC port!";
      this->cam_port_ = o3d3xx::DEFAULT_PCIC_PORT;
    }

  LOG(INFO) << "Camera connection info: ip=" << this->cam_ip_
            << ", port=" << this->cam_port_;

  this->endpoint_ =
    boost::asio::ip::tcp::endpoint(
      boost::asio::ip::address::from_string(this->cam_ip_), this->cam_port_);

  this->thread_ =
    std::unique_ptr<std::thread>(
      new std::thread(std::bind(&o3d3xx::FrameGrabber::Run, this)));
}

o3d3xx::FrameGrabber::~FrameGrabber()
{
  DLOG(INFO) << "FrameGrabber dtor running...";

  if (this->thread_ && this->thread_->joinable())
    {
      // NOTE: If Stop() was already called, that is fine
      // because the ASIO event loop is already done so the posted exception
      // will never get emitted.
      this->Stop();
      this->thread_->join();
    }

  DLOG(INFO) << "FrameGrabber done.";
}

void
o3d3xx::FrameGrabber::SetSchemaBuffer(std::uint16_t mask)
{
  std::string schema = o3d3xx::make_pcic_schema(mask);
  int c_len = 4 + 1 + 9 + schema.size() + 2;
  std::ostringstream str;
  str << o3d3xx::TICKET_c
      << 'L' << std::setfill('0') << std::setw(9) << c_len
      << '\r' << '\n'
      << o3d3xx::TICKET_c << 'c'
      << std::setfill('0') << std::setw(9)
      << schema.size()
      << schema
      << '\r' << '\n';

  std::string c_command = str.str();
  this->schema_buffer_.assign(c_command.begin(), c_command.end());
  DLOG(INFO) << "c_command: " << c_command;
}

void
o3d3xx::FrameGrabber::SetTriggerBuffer()
{
  int t_len = 4 + 1 + 2;
  std::ostringstream str;
  str << o3d3xx::TICKET_t
      << 'L' << std::setfill('0') << std::setw(9) << t_len
      << '\r' << '\n'
      << o3d3xx::TICKET_t << 't' << '\r' << '\n';

  std::string t_command = str.str();
  this->trigger_buffer_.assign(t_command.begin(), t_command.end());
}

void
o3d3xx::FrameGrabber::SWTrigger()
{
  int i = 0;
  while (! this->pcic_ready_.load())
    {
      std::this_thread::sleep_for(std::chrono::milliseconds(1));
      i++;

      if (i > 2000)
        {
          LOG(WARNING) << "pcic_ready_ flag not set!";
          return;
        }
    }

  this->io_service_.post(
    [=]()
    {
      boost::asio::async_write(
        this->sock_,
        boost::asio::buffer(this->trigger_buffer_.data(),
                            this->trigger_buffer_.size()),
        [=] (const boost::system::error_code& ec,
             std::size_t bytes_transferred)
        {
          if (ec) { throw o3d3xx::error_t(ec.value()); }
        });
    });
}

void
o3d3xx::FrameGrabber::Stop()
{
  this->io_service_.post([]() {
      throw o3d3xx::error_t(O3D3XX_THREAD_INTERRUPTED); });
}

bool
o3d3xx::FrameGrabber::WaitForFrame(o3d3xx::ByteBuffer* buff,
                                   long timeout_millis,
                                   bool copy_buff,
                                   bool organize)
{
  // mutex will unlock in `unique_lock' dtor if not explicitly unlocked prior
  std::unique_lock<std::mutex> lock(this->front_buffer_mutex_);

  try
    {
      // Store the current pointer backing the front buffer - this will be the
      // condition checked by the condition_variable predicate (pointer should
      // have changed) below
      std::uint8_t* initial_buff_ptr = this->front_buffer_.data();
      auto predicate =
        [this, initial_buff_ptr]()
	{
	  return this->front_buffer_.data() != initial_buff_ptr;
	};

      if (timeout_millis <= 0)
        {
          this->front_buffer_cv_.wait(lock, predicate);
        }
      else
        {
          if (!this->front_buffer_cv_.wait_for(
                lock,
	        std::chrono::milliseconds(timeout_millis),
	        predicate))
            {
              LOG(WARNING) << "Timeout waiting for image buffer from camera";
              return false;
            }
        }
    }
  catch (const std::system_error& ex)
    {
      LOG(WARNING) << "WaitForFrame: " << ex.what();
      return false;
    }

  DLOG(INFO) << "Client fetching new image data";
  buff->SetBytes(this->front_buffer_, copy_buff);
  lock.unlock();

  if (organize)
    {
      buff->Organize();
    }

  return true;
}

void
o3d3xx::FrameGrabber::ImageHandler(const boost::system::error_code& ec,
                                   std::size_t bytes_transferred,
                                   std::size_t bytes_read)
{
  if (ec) { throw o3d3xx::error_t(ec.value()); }

  bytes_read += bytes_transferred;

  if (bytes_read != this->back_buffer_.size())
    {
      this->sock_.async_read_some(
        boost::asio::buffer(&this->back_buffer_[bytes_read],
                            this->back_buffer_.size() - bytes_read),
        std::bind(&o3d3xx::FrameGrabber::ImageHandler, this,
                  std::placeholders::_1, std::placeholders::_2, bytes_read));
      return;
    }

  if (o3d3xx::verify_image_buffer(this->back_buffer_))
    {
      // Move data to front buffer in O(1)
      this->front_buffer_mutex_.lock();
      this->back_buffer_.swap(this->front_buffer_);
      this->front_buffer_mutex_.unlock();

      // notify waiting clients
      this->front_buffer_cv_.notify_all();
    }
  else
    {
      LOG(WARNING) << "Bad image!";
    }

  this->ticket_buffer_.clear();
  this->ticket_buffer_.resize(o3d3xx::TICKET_ID_SZ);
  this->sock_.async_read_some(
    boost::asio::buffer(this->ticket_buffer_.data(),
                        o3d3xx::TICKET_ID_SZ),
    std::bind(&o3d3xx::FrameGrabber::TicketHandler, this,
              std::placeholders::_1, std::placeholders::_2, 0));
}

void
o3d3xx::FrameGrabber::TicketHandler(const boost::system::error_code& ec,
                                    std::size_t bytes_transferred,
                                    std::size_t bytes_read)
{
  if (ec) { throw o3d3xx::error_t(ec.value()); }

  bytes_read += bytes_transferred;

  if (bytes_read < o3d3xx::TICKET_ID_SZ)
    {
      bytes_read +=
        boost::asio::read(
          this->sock_,
          boost::asio::buffer(&this->ticket_buffer_[bytes_read],
                              o3d3xx::TICKET_ID_SZ - bytes_read));

      if (bytes_read != o3d3xx::TICKET_ID_SZ)
        {
          LOG(ERROR) << "Timeout reading ticket!";
          throw o3d3xx::error_t(O3D3XX_IO_ERROR);
        }
    }

  std::string ticket;
  ticket.assign(this->ticket_buffer_.begin(),
                this->ticket_buffer_.begin() + 4);

  std::string payload_sz_str;
  payload_sz_str.assign(this->ticket_buffer_.begin()+5,
                        this->ticket_buffer_.begin()+14);
  int payload_sz = std::stoi(payload_sz_str);
  int ticket_sz = o3d3xx::TICKET_ID_SZ;

  if (ticket != o3d3xx::TICKET_image)
    {
      this->ticket_buffer_.resize(ticket_sz + payload_sz);

      bytes_read +=
        boost::asio::read(
          this->sock_,
          boost::asio::buffer(&this->ticket_buffer_[bytes_read],
                              (ticket_sz + payload_sz) - bytes_read));

      if (bytes_read != (ticket_sz + payload_sz))
        {
          LOG(ERROR) << "Timeout reading whole response!";
          LOG(ERROR) << "Got " << bytes_read << " bytes of "
                     << ticket_sz << " bytes expected";

          throw o3d3xx::error_t(O3D3XX_IO_ERROR);
        }
    }

  std::string ticket_str;
  ticket_str.assign(this->ticket_buffer_.begin(),
                    this->ticket_buffer_.end());
  DLOG(INFO) << "Ticket Full: '" << ticket_str << "'";

  if (ticket == o3d3xx::TICKET_image)
    {
      if (o3d3xx::verify_ticket_buffer(this->ticket_buffer_))
        {
          this->back_buffer_.resize(
            o3d3xx::get_image_buffer_size(this->ticket_buffer_));

          this->sock_.async_read_some(
            boost::asio::buffer(this->back_buffer_.data(),
                                this->back_buffer_.size()),
            std::bind(&o3d3xx::FrameGrabber::ImageHandler, this,
                      std::placeholders::_1, std::placeholders::_2, 0));
          return;
        }
      else
        {
          LOG(ERROR) << "Bad image ticket: " << ticket_str;
          throw(o3d3xx::error_t(O3D3XX_PCIC_BAD_REPLY));
        }
    }
  else if ((ticket == o3d3xx::TICKET_c) ||
           (ticket == o3d3xx::TICKET_t))
    {
      if (this->ticket_buffer_.at(20) != '*')
        {
          LOG(ERROR) << "Bad ticket: " << ticket_str;

          if ((ticket == o3d3xx::TICKET_t) &&
              (this->ticket_buffer_.at(20) == '!'))
            {
              LOG(WARNING) << "Are you software triggering in free run mode?";
            }
          else
            {
              throw(o3d3xx::error_t(O3D3XX_PCIC_BAD_REPLY));
            }
        }

      this->ticket_buffer_.clear();
      this->ticket_buffer_.resize(o3d3xx::TICKET_ID_SZ);
      this->sock_.async_read_some(
        boost::asio::buffer(this->ticket_buffer_.data(),
                            o3d3xx::TICKET_ID_SZ),
        std::bind(&o3d3xx::FrameGrabber::TicketHandler, this,
                  std::placeholders::_1, std::placeholders::_2, 0));

      return;
    }
  else
    {
      LOG(WARNING) << "Unexpected ticket: " << ticket;
      LOG(WARNING) << "Ticket Full: '" << ticket_str << "'";
      //throw(std::logic_error("Unexpected ticket type: " + ticket));

      this->ticket_buffer_.clear();
      this->ticket_buffer_.resize(o3d3xx::TICKET_ID_SZ);
      this->sock_.async_read_some(
        boost::asio::buffer(this->ticket_buffer_.data(),
                            o3d3xx::TICKET_ID_SZ),
        std::bind(&o3d3xx::FrameGrabber::TicketHandler, this,
                  std::placeholders::_1, std::placeholders::_2, 0));

      return;
    }
}

void
o3d3xx::FrameGrabber::Run()
{
  boost::asio::io_service::work work(this->io_service_);

  auto result_schema_write_handler =
    [&, this]
    (const boost::system::error_code& ec, std::size_t bytes_transferred)
    {
      if (ec) { throw o3d3xx::error_t(ec.value()); }
      this->ticket_buffer_.clear();
      this->ticket_buffer_.resize(o3d3xx::TICKET_ID_SZ);

      this->sock_.async_read_some(
        boost::asio::buffer(this->ticket_buffer_.data(),
                            o3d3xx::TICKET_ID_SZ),
        std::bind(&o3d3xx::FrameGrabber::TicketHandler,
                  this, std::placeholders::_1,
                  std::placeholders::_2, 0));

      this->pcic_ready_.store(true);
    };

  //
  // Establish TCP connection to sensor and
  // set PCIC schema for this session
  //
  try
    {
      this->sock_.async_connect(
        this->endpoint_,
        [&, this] (const boost::system::error_code& ec)
        {
          if (ec) { throw o3d3xx::error_t(ec.value()); }
          boost::asio::async_write(
            this->sock_,
            boost::asio::buffer(this->schema_buffer_.data(),
                                this->schema_buffer_.size()),
            result_schema_write_handler);
        });

      this->io_service_.run();
    }
  catch (const std::exception& ex)
    {
      LOG(WARNING) << "Exception: " << ex.what();
    }

  LOG(INFO) << "Framegrabber thread done.";
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: unomodel.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: kz $ $Date: 2004-02-25 16:44:39 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "unomodel.hxx"

#ifndef _VOS_MUTEX_HXX_
#include <vos/mutex.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

#include <sfx2/docfac.hxx>
#include <sfx2/objsh.hxx>

#include <iderdll.hxx>
#include <basdoc.hxx>

using namespace ::vos;
using namespace ::rtl;
using namespace ::cppu;
using namespace ::std;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;

SIDEModel::SIDEModel( SfxObjectShell *pObjSh )
: SfxBaseModel(pObjSh)
{
}

SIDEModel::~SIDEModel()
{
}

uno::Any SAL_CALL SIDEModel::queryInterface( const uno::Type& rType ) throw(uno::RuntimeException)
{
    uno::Any aRet =  ::cppu::queryInterface ( rType,
                                    // OWeakObject interfaces
                                    reinterpret_cast< XInterface* > ( this ),
                                    static_cast< XWeak* > ( this ),
                                    static_cast< XServiceInfo*  > ( this ) );
    if (!aRet.hasValue())
        aRet = SfxBaseModel::queryInterface ( rType );
    return aRet;
}

void SAL_CALL SIDEModel::acquire() throw()
{
    ::vos::OGuard aGuard(Application::GetSolarMutex());
    OWeakObject::acquire();
}

void SAL_CALL SIDEModel::release() throw()
{
    ::vos::OGuard aGuard(Application::GetSolarMutex());
    OWeakObject::release();
}

uno::Sequence< uno::Type > SAL_CALL SIDEModel::getTypes(  ) throw(uno::RuntimeException)
{
    uno::Sequence< uno::Type > aTypes = SfxBaseModel::getTypes();
    sal_Int32 nLen = aTypes.getLength();
    aTypes.realloc(nLen + 1);
    uno::Type* pTypes = aTypes.getArray();
    pTypes[nLen++] = ::getCppuType((Reference<XServiceInfo>*)0);

    return aTypes;
}

OUString SIDEModel::getImplementationName(void) throw( uno::RuntimeException )
{
    return getImplementationName_Static();
}

::rtl::OUString SIDEModel::getImplementationName_Static()
{
    return rtl::OUString::createFromAscii("com.sun.star.comp.basic.BasicIDE");
}

sal_Bool SIDEModel::supportsService(const OUString& rServiceName) throw( uno::RuntimeException )
{
    return rServiceName == ::rtl::OUString::createFromAscii("com.sun.star.script.BasicIDE");
}
uno::Sequence< OUString > SIDEModel::getSupportedServiceNames(void) throw( uno::RuntimeException )
{
    return getSupportedServiceNames_Static();
}

uno::Sequence< OUString > SIDEModel::getSupportedServiceNames_Static(void)
{
    uno::Sequence< OUString > aRet(1);
    OUString* pArray = aRet.getArray();
    pArray[0] = ::rtl::OUString::createFromAscii("com.sun.star.script.BasicIDE");
    return aRet;
}

uno::Reference< uno::XInterface > SAL_CALL SIDEModel_createInstance(
                const uno::Reference< lang::XMultiServiceFactory > & rSMgr ) throw( uno::Exception )
{
    ::vos::OGuard aGuard( Application::GetSolarMutex() );
    BasicIDEDLL::Init();
    SfxObjectShell* pShell = new BasicDocShell();
    return uno::Reference< uno::XInterface >( pShell->GetModel() );
}

<commit_msg>INTEGRATION: CWS ooo19126 (1.4.206); FILE MERGED 2005/09/05 13:55:50 rt 1.4.206.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: unomodel.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 20:12:34 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "unomodel.hxx"

#ifndef _VOS_MUTEX_HXX_
#include <vos/mutex.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

#include <sfx2/docfac.hxx>
#include <sfx2/objsh.hxx>

#include <iderdll.hxx>
#include <basdoc.hxx>

using namespace ::vos;
using namespace ::rtl;
using namespace ::cppu;
using namespace ::std;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;

SIDEModel::SIDEModel( SfxObjectShell *pObjSh )
: SfxBaseModel(pObjSh)
{
}

SIDEModel::~SIDEModel()
{
}

uno::Any SAL_CALL SIDEModel::queryInterface( const uno::Type& rType ) throw(uno::RuntimeException)
{
    uno::Any aRet =  ::cppu::queryInterface ( rType,
                                    // OWeakObject interfaces
                                    reinterpret_cast< XInterface* > ( this ),
                                    static_cast< XWeak* > ( this ),
                                    static_cast< XServiceInfo*  > ( this ) );
    if (!aRet.hasValue())
        aRet = SfxBaseModel::queryInterface ( rType );
    return aRet;
}

void SAL_CALL SIDEModel::acquire() throw()
{
    ::vos::OGuard aGuard(Application::GetSolarMutex());
    OWeakObject::acquire();
}

void SAL_CALL SIDEModel::release() throw()
{
    ::vos::OGuard aGuard(Application::GetSolarMutex());
    OWeakObject::release();
}

uno::Sequence< uno::Type > SAL_CALL SIDEModel::getTypes(  ) throw(uno::RuntimeException)
{
    uno::Sequence< uno::Type > aTypes = SfxBaseModel::getTypes();
    sal_Int32 nLen = aTypes.getLength();
    aTypes.realloc(nLen + 1);
    uno::Type* pTypes = aTypes.getArray();
    pTypes[nLen++] = ::getCppuType((Reference<XServiceInfo>*)0);

    return aTypes;
}

OUString SIDEModel::getImplementationName(void) throw( uno::RuntimeException )
{
    return getImplementationName_Static();
}

::rtl::OUString SIDEModel::getImplementationName_Static()
{
    return rtl::OUString::createFromAscii("com.sun.star.comp.basic.BasicIDE");
}

sal_Bool SIDEModel::supportsService(const OUString& rServiceName) throw( uno::RuntimeException )
{
    return rServiceName == ::rtl::OUString::createFromAscii("com.sun.star.script.BasicIDE");
}
uno::Sequence< OUString > SIDEModel::getSupportedServiceNames(void) throw( uno::RuntimeException )
{
    return getSupportedServiceNames_Static();
}

uno::Sequence< OUString > SIDEModel::getSupportedServiceNames_Static(void)
{
    uno::Sequence< OUString > aRet(1);
    OUString* pArray = aRet.getArray();
    pArray[0] = ::rtl::OUString::createFromAscii("com.sun.star.script.BasicIDE");
    return aRet;
}

uno::Reference< uno::XInterface > SAL_CALL SIDEModel_createInstance(
                const uno::Reference< lang::XMultiServiceFactory > & rSMgr ) throw( uno::Exception )
{
    ::vos::OGuard aGuard( Application::GetSolarMutex() );
    BasicIDEDLL::Init();
    SfxObjectShell* pShell = new BasicDocShell();
    return uno::Reference< uno::XInterface >( pShell->GetModel() );
}

<|endoftext|>


<commit_before><commit_msg>Removes move in types.hpp which could prevent RVO<commit_after><|endoftext|>


<commit_before>//
// Created by dar on 1/25/16.
//

#include <render/block/ChunkRender.h>
#include <render/entity/PlayerRender.h>
#include <render/entity/SimpleShapeRender.h>
#include "../RenderManager.h"
#include "GameRender.h"
#include "../../window/Game.h"
#include "../../core/Core.h"
#include <core/map/entity/EntityBullet.h>
#include <core/map/entity/EntityFather.h>
#include <core/map/entity/EntityMachinery.h>
#include <core/map/entity/EntityDoor.h>
#include <core/map/entity/EntityFurniture.h>
#include <core/map/entity/EntityTable.h>
#include <core/map/entity/EntityGlassDebris.h>
#include <core/map/entity/EntityCouch.h>
#include <core/map/block/SimpleBlock.h>
#include <logging.h>
#include <render/entity/EntityMachineryRender.h>
#include <render/entity/EntityStaticRender.h>
#include <render/entity/EntityWideRender.h>

GameRender::GameRender() : WindowRender() { }

void GameRender::init(RenderContext *const renderContext) {
    this->initRenders();
    fbo.init(3, renderContext->getWindowWidth(), renderContext->getWindowHeight(), new float[4]{0.9, 0.9, 0.9, 1.0}, "fboshader");
    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    this->resize(renderContext);
}

void GameRender::resize(RenderContext *const renderContext) {
    viewMatrix = glm::lookAt(glm::vec3(0, 0, 0.0f), glm::vec3(0, 0, 1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    this->projectionMatrix = glm::ortho(0.0f, float(renderContext->getWindowWidth()), 0.0f, float(renderContext->getWindowHeight()));
    this->fbo.resize(renderContext->getWindowWidth(), renderContext->getWindowHeight());
}

void GameRender::render(Window *window, RenderContext *const renderContext) {
    Game *game = ((Game *) window);
    Core *core = game->getCore();

    unsigned int windowWidth = renderContext->getWindowWidth();
    unsigned int windowHeight = renderContext->getWindowHeight();
    double scale = core->getBlockSize() * core->getGeneralScale();

    double camX = core->getCamX() * (core->getBlockSize() * core->getGeneralScale());
    double camY = core->getCamY() * (core->getBlockSize() * core->getGeneralScale());

    fbo.bind();
    glClearColor(0.9, 0.9, 0.9, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    scale *= Chunk::size;
    for (Chunk *const chunk : core->getMap()->getChunks()) {
        getChunkRender()->render(chunk, projectionMatrix, glm::translate(viewMatrix, glm::vec3(
            -(signed) windowWidth / 2.0f - camX,
            (signed) windowHeight / 2.0f - camY, 0.0f
        )), core->getBlockSize() * core->getGeneralScale());
        chunk->setRedrawn();
    }
    scale /= Chunk::size;
    int entitiesNum = 0;
    for (int i = core->getMap()->getEntities().size() - 1; i >= 0; i--) {
        Entity *entity = core->getMap()->getEntities().at(i);
        double maxSize = entity->getWidth() > entity->getHeight() ? entity->getWidth() : entity->getHeight();
        if (entity->getX() * scale > -(signed) windowWidth / 2.0f - camX &&
            (entity->getX() - 1 - maxSize) * scale < -(signed) windowWidth / 2.0f - camX + (signed) windowWidth &&
            entity->getY() * scale > -(signed) windowHeight / 2.0f - camY &&
            (entity->getY() - 1 - maxSize) * scale < -(signed) windowHeight / 2.0f - camY + (signed) windowHeight) {
            getEntityRender(entity)->render(entity, projectionMatrix, glm::translate(viewMatrix, glm::vec3(
                -(signed) windowWidth / 2.0f - camX,
                (signed) windowHeight / 2.0f - camY,
                0.0f)), core->getBlockSize() * core->getGeneralScale());
            if (IEntityLighted *elighted = dynamic_cast<IEntityLighted *>(entity)) {
                fbo.getShaderProgram()->useProgram();
                if (entitiesNum < fbo.MAX_LIGHT_SRCS) {
                    char *uniform_name_formatted = new char[16 + (int) log((double) fbo.MAX_LIGHT_SRCS)];
                    sprintf(uniform_name_formatted, "lightPoints[%d]", entitiesNum);
                    fbo.getShaderProgram()->setUniform(uniform_name_formatted, glm::vec2(
                        camX + (entity->getX() - 1 + entity->getWidth() / 2) * scale + (double) windowWidth / 2,
                        -camY - (entity->getY() - 1 + entity->getHeight() / 2) * scale + (double) windowHeight / 2));
                    entitiesNum++;
                }
            }
        }
    }

#ifndef EDITOR
    //TODO
    static int grayout[][4] = {{20, 3, 4, 6},
                               {21, 9, 1, 1},
                               {25, 3, 5, 3},
                               {30, 3, 1, 1},
                               {31, 3, 4, 3},
                               {35, 4, 1, 1},
                               {34, 6, 1, 1},
                               {31, 7, 7, 11}};

    /*for (int i = 0; i < 8; i++) {
        this->voidRender->render(grayout[i][0], grayout[i][1], grayout[i][2], grayout[i][3], projectionMatrix, glm::translate(viewMatrix, glm::vec3(
            -(signed) windowWidth / 2.0f - camX,
            (signed) windowHeight / 2.0f - camY,
            0.0f)), core->getBlockSize() * core->getGeneralScale());
    }*/
#endif //EDITOR

    fbo.unbind();
    fbo.getShaderProgram()->useProgram();
    fbo.getShaderProgram()->setUniform("lightPointsNum", entitiesNum);
    fbo.getShaderProgram()->setUniform("scale", (float) (core->getBlockSize() * core->getGeneralScale()));
    fbo.render(0);

#if !defined(EDITOR) && !defined(DEBUG)
    float voidAlpha = 1.0f;
    if (game->getCore()->getMap()->getWorldTime() > 21.25f) {
        voidAlpha = std::max(0.0f, 22.25f - (float) game->getCore()->getMap()->getWorldTime());
    }

    this->voidRender->render(0, 0, windowWidth + 1, windowHeight + 1, projectionMatrix, glm::translate(viewMatrix, glm::vec3(
        0,
        (int) ((signed) windowHeight),
        0.0f)), 1.0f, 0.7f, 0.7f, 0.7f, voidAlpha);
#endif

    for (GuiElement *guiElement : game->getGuiElements()) {
        renderContext->getGuiElementRender(guiElement)->render(guiElement, projectionMatrix, glm::translate(viewMatrix, glm::vec3(
            0,
            (int) ((signed) windowHeight),
            0.0f)), core->getGeneralScale());
    }
}

ChunkRender *GameRender::getChunkRender() const {
    return this->chunkRender;
}

EntityRender *GameRender::getEntityRender(const Entity *const entity) {
    EntityRender *r = entityRenders[typeid(*entity).name()];
    if (r == nullptr) {
        if (const EntityFurniture *const f = dynamic_cast<const EntityFurniture *const>(entity)) {
            return entityRenders[typeid(EntityFurniture).name()];
        } else {
            return nullptr;
        }
    }
    return r;
}

void GameRender::cleanRenders() {
    delete this->voidRender;
    delete this->chunkRender;

    for (std::pair<const char *, EntityRender *> renderPair : entityRenders) {
        delete renderPair.second;
    }
    entityRenders.clear();
}

void GameRender::initRenders() {
    this->voidRender = new VoidRender();
    this->chunkRender = new ChunkRender();

    entityRenders.insert(std::make_pair(typeid(EntityPlayer).name(), new PlayerRender()));
    EntityMachineryRender *machineryRender = new EntityMachineryRender();
    entityRenders.insert(std::make_pair(typeid(EntityTruck).name(), machineryRender));
    entityRenders.insert(std::make_pair(typeid(EntityBulldozer).name(), machineryRender));
    entityRenders.insert(std::make_pair(typeid(EntityHoover).name(), machineryRender));
    //entityRenders.insert(std::make_pair(typeid(EntityBullet).name(), new DefaultEntityRender("bullet", "shader")));
    EntityWideRender *wideRender = new EntityWideRender();
    entityRenders.insert(std::make_pair(typeid(EntityTable).name(), wideRender));
    entityRenders.insert(std::make_pair(typeid(EntityCoffeeTable).name(), wideRender));
    entityRenders.insert(std::make_pair(typeid(EntityCouch).name(), wideRender));
    EntityStaticRender *staticRender = new EntityStaticRender();
    entityRenders.insert(std::make_pair(typeid(EntityFurniture).name(), staticRender));
    entityRenders.insert(std::make_pair(typeid(EntityGlassDebris).name(), staticRender));
    entityRenders.insert(std::make_pair(typeid(SimpleShape).name(), new SimpleShapeRender()));
    entityRenders.insert(std::make_pair(typeid(EntityFather).name(), new DefaultEntityRender("parents", "shader")));
}

GameRender::~GameRender() {
    cleanRenders();
}

<commit_msg>Reenabled grayouts<commit_after>//
// Created by dar on 1/25/16.
//

#include <render/block/ChunkRender.h>
#include <render/entity/PlayerRender.h>
#include <render/entity/SimpleShapeRender.h>
#include "../RenderManager.h"
#include "GameRender.h"
#include "../../window/Game.h"
#include "../../core/Core.h"
#include <core/map/entity/EntityBullet.h>
#include <core/map/entity/EntityFather.h>
#include <core/map/entity/EntityMachinery.h>
#include <core/map/entity/EntityDoor.h>
#include <core/map/entity/EntityFurniture.h>
#include <core/map/entity/EntityTable.h>
#include <core/map/entity/EntityGlassDebris.h>
#include <core/map/entity/EntityCouch.h>
#include <core/map/block/SimpleBlock.h>
#include <logging.h>
#include <render/entity/EntityMachineryRender.h>
#include <render/entity/EntityStaticRender.h>
#include <render/entity/EntityWideRender.h>

GameRender::GameRender() : WindowRender() { }

void GameRender::init(RenderContext *const renderContext) {
    this->initRenders();
    fbo.init(3, renderContext->getWindowWidth(), renderContext->getWindowHeight(), new float[4]{0.9, 0.9, 0.9, 1.0}, "fboshader");
    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    this->resize(renderContext);
}

void GameRender::resize(RenderContext *const renderContext) {
    viewMatrix = glm::lookAt(glm::vec3(0, 0, 0.0f), glm::vec3(0, 0, 1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    this->projectionMatrix = glm::ortho(0.0f, float(renderContext->getWindowWidth()), 0.0f, float(renderContext->getWindowHeight()));
    this->fbo.resize(renderContext->getWindowWidth(), renderContext->getWindowHeight());
}

void GameRender::render(Window *window, RenderContext *const renderContext) {
    Game *game = ((Game *) window);
    Core *core = game->getCore();

    unsigned int windowWidth = renderContext->getWindowWidth();
    unsigned int windowHeight = renderContext->getWindowHeight();
    double scale = core->getBlockSize() * core->getGeneralScale();

    double camX = core->getCamX() * (core->getBlockSize() * core->getGeneralScale());
    double camY = core->getCamY() * (core->getBlockSize() * core->getGeneralScale());

    fbo.bind();
    glClearColor(0.9, 0.9, 0.9, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    scale *= Chunk::size;
    for (Chunk *const chunk : core->getMap()->getChunks()) {
        getChunkRender()->render(chunk, projectionMatrix, glm::translate(viewMatrix, glm::vec3(
            -(signed) windowWidth / 2.0f - camX,
            (signed) windowHeight / 2.0f - camY, 0.0f
        )), core->getBlockSize() * core->getGeneralScale());
        chunk->setRedrawn();
    }
    scale /= Chunk::size;
    int entitiesNum = 0;
    for (int i = core->getMap()->getEntities().size() - 1; i >= 0; i--) {
        Entity *entity = core->getMap()->getEntities().at(i);
        double maxSize = entity->getWidth() > entity->getHeight() ? entity->getWidth() : entity->getHeight();
        if (entity->getX() * scale > -(signed) windowWidth / 2.0f - camX &&
            (entity->getX() - 1 - maxSize) * scale < -(signed) windowWidth / 2.0f - camX + (signed) windowWidth &&
            entity->getY() * scale > -(signed) windowHeight / 2.0f - camY &&
            (entity->getY() - 1 - maxSize) * scale < -(signed) windowHeight / 2.0f - camY + (signed) windowHeight) {
            getEntityRender(entity)->render(entity, projectionMatrix, glm::translate(viewMatrix, glm::vec3(
                -(signed) windowWidth / 2.0f - camX,
                (signed) windowHeight / 2.0f - camY,
                0.0f)), core->getBlockSize() * core->getGeneralScale());
            if (IEntityLighted *elighted = dynamic_cast<IEntityLighted *>(entity)) {
                fbo.getShaderProgram()->useProgram();
                if (entitiesNum < fbo.MAX_LIGHT_SRCS) {
                    char *uniform_name_formatted = new char[16 + (int) log((double) fbo.MAX_LIGHT_SRCS)];
                    sprintf(uniform_name_formatted, "lightPoints[%d]", entitiesNum);
                    fbo.getShaderProgram()->setUniform(uniform_name_formatted, glm::vec2(
                        camX + (entity->getX() - 1 + entity->getWidth() / 2) * scale + (double) windowWidth / 2,
                        -camY - (entity->getY() - 1 + entity->getHeight() / 2) * scale + (double) windowHeight / 2));
                    entitiesNum++;
                }
            }
        }
    }

#ifndef EDITOR
    //TODO
    static int grayout[][4] = {{20, 3, 4, 6},
                               {21, 9, 1, 1},
                               {25, 3, 5, 3},
                               {30, 3, 1, 1},
                               {31, 3, 4, 3},
                               {35, 4, 1, 1},
                               {34, 6, 1, 1},
                               {31, 7, 7, 11}};

    for (int i = 0; i < 8; i++) {
        this->voidRender->render(grayout[i][0], grayout[i][1], grayout[i][2], grayout[i][3], projectionMatrix, glm::translate(viewMatrix, glm::vec3(
            -(signed) windowWidth / 2.0f - camX,
            (signed) windowHeight / 2.0f - camY,
            0.0f)), core->getBlockSize() * core->getGeneralScale());
    }
#endif //EDITOR

    fbo.unbind();
    fbo.getShaderProgram()->useProgram();
    fbo.getShaderProgram()->setUniform("lightPointsNum", entitiesNum);
    fbo.getShaderProgram()->setUniform("scale", (float) (core->getBlockSize() * core->getGeneralScale()));
    fbo.render(0);

#if !defined(EDITOR) && !defined(DEBUG)
    float voidAlpha = 1.0f;
    if (game->getCore()->getMap()->getWorldTime() > 21.25f) {
        voidAlpha = std::max(0.0f, 22.25f - (float) game->getCore()->getMap()->getWorldTime());
    }

    this->voidRender->render(0, 0, windowWidth + 1, windowHeight + 1, projectionMatrix, glm::translate(viewMatrix, glm::vec3(
        0,
        (int) ((signed) windowHeight),
        0.0f)), 1.0f, 0.7f, 0.7f, 0.7f, voidAlpha);
#endif

    for (GuiElement *guiElement : game->getGuiElements()) {
        renderContext->getGuiElementRender(guiElement)->render(guiElement, projectionMatrix, glm::translate(viewMatrix, glm::vec3(
            0,
            (int) ((signed) windowHeight),
            0.0f)), core->getGeneralScale());
    }
}

ChunkRender *GameRender::getChunkRender() const {
    return this->chunkRender;
}

EntityRender *GameRender::getEntityRender(const Entity *const entity) {
    EntityRender *r = entityRenders[typeid(*entity).name()];
    if (r == nullptr) {
        if (const EntityFurniture *const f = dynamic_cast<const EntityFurniture *const>(entity)) {
            return entityRenders[typeid(EntityFurniture).name()];
        } else {
            return nullptr;
        }
    }
    return r;
}

void GameRender::cleanRenders() {
    delete this->voidRender;
    delete this->chunkRender;

    for (std::pair<const char *, EntityRender *> renderPair : entityRenders) {
        delete renderPair.second;
    }
    entityRenders.clear();
}

void GameRender::initRenders() {
    this->voidRender = new VoidRender();
    this->chunkRender = new ChunkRender();

    entityRenders.insert(std::make_pair(typeid(EntityPlayer).name(), new PlayerRender()));
    EntityMachineryRender *machineryRender = new EntityMachineryRender();
    entityRenders.insert(std::make_pair(typeid(EntityTruck).name(), machineryRender));
    entityRenders.insert(std::make_pair(typeid(EntityBulldozer).name(), machineryRender));
    entityRenders.insert(std::make_pair(typeid(EntityHoover).name(), machineryRender));
    //entityRenders.insert(std::make_pair(typeid(EntityBullet).name(), new DefaultEntityRender("bullet", "shader")));
    EntityWideRender *wideRender = new EntityWideRender();
    entityRenders.insert(std::make_pair(typeid(EntityTable).name(), wideRender));
    entityRenders.insert(std::make_pair(typeid(EntityCoffeeTable).name(), wideRender));
    entityRenders.insert(std::make_pair(typeid(EntityCouch).name(), wideRender));
    EntityStaticRender *staticRender = new EntityStaticRender();
    entityRenders.insert(std::make_pair(typeid(EntityFurniture).name(), staticRender));
    entityRenders.insert(std::make_pair(typeid(EntityGlassDebris).name(), staticRender));
    entityRenders.insert(std::make_pair(typeid(SimpleShape).name(), new SimpleShapeRender()));
    entityRenders.insert(std::make_pair(typeid(EntityFather).name(), new DefaultEntityRender("parents", "shader")));
}

GameRender::~GameRender() {
    cleanRenders();
}

<|endoftext|>