BVB Source Codes

CRYENGINE Show PersistantDebug.cpp Source code

Return Download CRYENGINE: download PersistantDebug.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "PersistantDebug.h"
  5. #include "CryAction.h"
  6. #include <CryRenderer/IRenderAuxGeom.h>
  7. #include <IUIDraw.h>
  8. #include <CrySystem/ILocalizationManager.h>
  9.  
  10. CPersistantDebug::CPersistantDebug()
  11.         : m_pETLog(nullptr)
  12.         , m_pETHideAll(nullptr)
  13.         , m_pETHideBehaviour(nullptr)
  14.         , m_pETHideReadability(nullptr)
  15.         , m_pETHideAIDebug(nullptr)
  16.         , m_pETHideFlowgraph(nullptr)
  17.         , m_pETHideScriptBind(nullptr)
  18.         , m_pETFontSizeMultiplier(nullptr)
  19.         , m_pETMaxDisplayDistance(nullptr)
  20.         , m_pETColorOverrideEnable(nullptr)
  21.         , m_pETColorOverrideR(nullptr)
  22.         , m_pETColorOverrideG(nullptr)
  23.         , m_pETColorOverrideB(nullptr)
  24. {
  25.         m_pDefaultFont = gEnv->pCryFont->GetFont("default");
  26.         CRY_ASSERT(m_pDefaultFont);
  27. }
  28.  
  29. void CPersistantDebug::Begin(const char* name, bool clear)
  30. {
  31.         if (clear)
  32.                 m_objects[name].clear();
  33.         else
  34.                 m_objects[name];
  35.         m_current = m_objects.find(name);
  36. }
  37.  
  38. void CPersistantDebug::AddSphere(const Vec3& pos, float radius, ColorF clr, float timeout)
  39. {
  40.         SObj obj;
  41.         obj.obj = eOT_Sphere;
  42.         obj.clr = clr;
  43.         obj.pos = pos;
  44.         obj.radius = radius;
  45.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  46.         obj.totalTime = obj.timeRemaining;
  47.         m_current->second.push_back(obj);
  48. }
  49.  
  50. void CPersistantDebug::AddQuat(const Vec3& pos, const Quat& q, float r, ColorF clr, float timeout)
  51. {
  52.         SObj obj;
  53.         obj.obj = eOT_Quat;
  54.         obj.clr = clr;
  55.         obj.pos = pos;
  56.         obj.q = q;
  57.         obj.radius = r;
  58.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  59.         obj.totalTime = obj.timeRemaining;
  60.         m_current->second.push_back(obj);
  61. }
  62.  
  63. void CPersistantDebug::AddAABB(const Vec3& min, const Vec3& max, ColorF clr, float timeout)
  64. {
  65.         SObj obj;
  66.         obj.obj = eOT_AABB;
  67.         obj.clr = clr;
  68.         obj.pos = min;
  69.         obj.dir = max;
  70.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  71.         obj.totalTime = obj.timeRemaining;
  72.         m_current->second.push_back(obj);
  73. }
  74.  
  75. void CPersistantDebug::AddDirection(const Vec3& pos, float radius, const Vec3& dir, ColorF clr, float timeout)
  76. {
  77.         SObj obj;
  78.         obj.obj = eOT_Arrow;
  79.         obj.clr = clr;
  80.         obj.pos = pos;
  81.         obj.radius = radius;
  82.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  83.         obj.totalTime = obj.timeRemaining;
  84.         obj.dir = dir.GetNormalizedSafe();
  85.         if (obj.dir.GetLengthSquared() > 0.001f)
  86.                 m_current->second.push_back(obj);
  87. }
  88.  
  89. void CPersistantDebug::AddLine(const Vec3& pos1, const Vec3& pos2, ColorF clr, float timeout)
  90. {
  91.         SObj obj;
  92.         obj.obj = eOT_Line;
  93.         obj.clr = clr;
  94.         obj.pos = pos1;
  95.         obj.dir = pos2 - pos1;
  96.         obj.radius = 0.0f;
  97.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  98.         obj.totalTime = obj.timeRemaining;
  99.         m_current->second.push_back(obj);
  100. }
  101.  
  102. void CPersistantDebug::AddPlanarDisc(const Vec3& pos, float innerRadius, float outerRadius, ColorF clr, float timeout)
  103. {
  104.         SObj obj;
  105.         obj.obj = eOT_Disc;
  106.         obj.clr = clr;
  107.         obj.pos = pos;
  108.         obj.radius = std::max(0.0f, std::min(innerRadius, outerRadius));
  109.         obj.radius2 = std::min(100.0f, std::max(0.0f, std::max(innerRadius, outerRadius)));
  110.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  111.         obj.totalTime = obj.timeRemaining;
  112.         if (obj.radius2)
  113.                 m_current->second.push_back(obj);
  114. }
  115.  
  116. void CPersistantDebug::AddCone(const Vec3& pos, const Vec3& dir, float baseRadius, float height, ColorF clr, float timeout)
  117. {
  118.         SObj obj;
  119.         obj.obj = eOT_Cone;
  120.         obj.clr = clr;
  121.         obj.pos = pos;
  122.         obj.dir = dir;
  123.         obj.radius = std::max(0.001f, baseRadius);
  124.         obj.radius2 = std::max(0.001f, height);
  125.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  126.         obj.totalTime = obj.timeRemaining;
  127.         m_current->second.push_back(obj);
  128. }
  129.  
  130. void CPersistantDebug::AddCylinder(const Vec3& pos, const Vec3& dir, float radius, float height, ColorF clr, float timeout)
  131. {
  132.         SObj obj;
  133.         obj.obj = eOT_Cylinder;
  134.         obj.clr = clr;
  135.         obj.pos = pos;
  136.         obj.dir = dir;
  137.         obj.radius = std::max(0.001f, radius);
  138.         obj.radius2 = std::max(0.001f, height);
  139.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  140.         obj.totalTime = obj.timeRemaining;
  141.         m_current->second.push_back(obj);
  142. }
  143.  
  144. void CPersistantDebug::AddText(float x, float y, float size, ColorF clr, float timeout, const char* fmt, ...)
  145. {
  146.         char buffer[4096];
  147.         va_list args;
  148.         va_start(args, fmt);
  149.         cry_vsprintf(buffer, fmt, args);
  150.         va_end(args);
  151.  
  152.         SObj obj;
  153.         obj.obj = eOT_Text2D;
  154.         obj.clr = clr;
  155.         obj.pos.x = x;
  156.         obj.pos.y = y;
  157.         obj.radius = size;
  158.         obj.text = buffer;
  159.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  160.         obj.totalTime = obj.timeRemaining;
  161.         m_current->second.push_back(obj);
  162. }
  163.  
  164. void CPersistantDebug::AddText3D(const Vec3& pos, float size, ColorF clr, float timeout, const char* fmt, ...)
  165. {
  166.         char buffer[4096];
  167.         va_list args;
  168.         va_start(args, fmt);
  169.         cry_vsprintf(buffer, fmt, args);
  170.         va_end(args);
  171.  
  172.         SObj obj;
  173.         obj.obj = eOT_Text3D;
  174.         obj.clr = clr;
  175.         obj.pos = pos;
  176.         obj.radius = size;
  177.         obj.text = buffer;
  178.         obj.timeRemaining = timeout < 0.0f ? kUnlimitedTime : timeout;
  179.         obj.totalTime = obj.timeRemaining;
  180.         m_current->second.push_back(obj);
  181. }
  182.  
  183. void CPersistantDebug::Add2DText(const char* text, float size, ColorF clr, float timeout)
  184. {
  185.         if (text == 0 || *text == '\0')
  186.                 return;
  187.  
  188.         STextObj2D obj;
  189.         obj.clr = clr;
  190.         obj.text = text;
  191.         obj.size = size;
  192.         obj.timeRemaining = timeout <= 0.0f ? kUnlimitedTime : timeout;
  193.         obj.totalTime = obj.timeRemaining;
  194.         m_2DTexts.push_front(obj);
  195. }
  196.  
  197. void CPersistantDebug::Add2DLine(float x1, float y1, float x2, float y2, ColorF clr, float timeout)
  198. {
  199.         int iScreenWidth = gEnv->pRenderer->GetWidth();
  200.         int iScreenHeight = gEnv->pRenderer->GetHeight();
  201.  
  202.         SObj obj;
  203.         obj.obj = eOT_Line2D;
  204.         obj.pos.x = x1 / iScreenWidth;
  205.         obj.pos.y = y1 / iScreenHeight;
  206.         obj.pos.z = 0;
  207.         obj.dir.x = x2 / iScreenWidth;
  208.         obj.dir.y = y2 / iScreenHeight;
  209.         obj.dir.z = 0;
  210.         obj.clr = clr;
  211.         obj.timeRemaining = timeout <= 0.0f ? kUnlimitedTime : timeout;
  212.         obj.totalTime = obj.timeRemaining;
  213.         m_current->second.push_back(obj);
  214. }
  215.  
  216. bool CPersistantDebug::Init()
  217. {
  218.         // Init CVars
  219.         m_pETLog = REGISTER_INT("cl_ETLog", 0, VF_DUMPTODISK, "Logging (0=off, 1=editor.log, 2=editor.log + AIlog.log)");
  220.         m_pETHideAll = REGISTER_INT("cl_ETHideAll", 0, VF_DUMPTODISK, "Hide all tags (overrides all other options)");
  221.         m_pETHideBehaviour = REGISTER_INT("cl_ETHideBehaviour", 0, VF_DUMPTODISK, "Hide AI behavior tags");
  222.         m_pETHideReadability = REGISTER_INT("cl_ETHideReadability", 0, VF_DUMPTODISK, "Hide AI readability tags");
  223.         m_pETHideAIDebug = REGISTER_INT("cl_ETHideAIDebug", 0, VF_DUMPTODISK, "Hide AI debug tags");
  224.         m_pETHideFlowgraph = REGISTER_INT("cl_ETHideFlowgraph", 0, VF_DUMPTODISK, "Hide tags created by flowgraph");
  225.         m_pETHideScriptBind = REGISTER_INT("cl_ETHideScriptBind", 0, VF_DUMPTODISK, "Hide tags created by Lua script");
  226.         m_pETFontSizeMultiplier = REGISTER_FLOAT("cl_ETFontSizeMultiplier", 1.0f, VF_DUMPTODISK, "Global font size multiplier");
  227.         m_pETMaxDisplayDistance = REGISTER_FLOAT("cl_ETMaxDisplayDistance", -2.0f, VF_DUMPTODISK, "Max display distance");
  228.         m_pETColorOverrideEnable = REGISTER_INT("cl_ETColorOverrideEnable", 0, VF_DUMPTODISK, "Global color override");
  229.         m_pETColorOverrideR = REGISTER_FLOAT("cl_ETColorOverrideR", 1.0f, VF_DUMPTODISK, "Global color override (RED)");
  230.         m_pETColorOverrideG = REGISTER_FLOAT("cl_ETColorOverrideG", 1.0f, VF_DUMPTODISK, "Global color override (GREEN)");
  231.         m_pETColorOverrideB = REGISTER_FLOAT("cl_ETColorOverrideB", 1.0f, VF_DUMPTODISK, "Global color override (BLUE)");
  232.  
  233.         Reset();
  234.  
  235.         return true;
  236. }
  237.  
  238. void CPersistantDebug::Reset()
  239. {
  240.         m_2DTexts.clear();
  241.         m_objects.clear();
  242.         Begin("default", true); // Safety context if first caller forgets to use Begin(), so we don't crash!
  243. }
  244.  
  245. void CPersistantDebug::Update(float frameTime)
  246. {
  247.         if (m_objects.empty())
  248.                 return;
  249.  
  250.         if (!gEnv->pRenderer)
  251.         {
  252.                 return;
  253.         }
  254.  
  255.         IRenderAuxGeom* pAux = gEnv->pRenderer->GetIRenderAuxGeom();
  256.         static const int flags3D = e_Mode3D | e_AlphaBlended | e_DrawInFrontOff | e_FillModeSolid | e_CullModeBack | e_DepthWriteOn | e_DepthTestOn;
  257.         static const int flags2D = e_Mode2D | e_AlphaBlended;
  258.  
  259.         std::vector<ListObj::iterator> toClear;
  260.         std::vector<MapListObj::iterator> toClearMap;
  261.         for (MapListObj::iterator iterMap = m_objects.begin(); iterMap != m_objects.end(); ++iterMap)
  262.         {
  263.                 toClear.resize(0);
  264.                 for (ListObj::iterator iterList = iterMap->second.begin(); iterList != iterMap->second.end(); ++iterList)
  265.                 {
  266.                         if (iterList->totalTime != kUnlimitedTime)
  267.                         {
  268.                                 iterList->timeRemaining -= frameTime;
  269.                                 if (iterList->timeRemaining <= 0.0f && !(iterList->obj == eOT_EntityTag && iterList->columns.size() > 1))
  270.                                 {
  271.                                         toClear.push_back(iterList);
  272.                                         continue;
  273.                                 }
  274.                         }
  275.  
  276.                         ColorF clr = iterList->clr;
  277.                         clr.a *= iterList->timeRemaining / iterList->totalTime;
  278.                         switch (iterList->obj)
  279.                         {
  280.                         case eOT_Sphere:
  281.                                 pAux->SetRenderFlags(flags3D);
  282.                                 pAux->DrawSphere(iterList->pos, iterList->radius, clr);
  283.                                 break;
  284.                         case eOT_Quat:
  285.                                 pAux->SetRenderFlags(flags3D);
  286.                                 {
  287.                                         float r = iterList->radius;
  288.                                         Vec3 x = r * iterList->q.GetColumn0();
  289.                                         Vec3 y = r * iterList->q.GetColumn1();
  290.                                         Vec3 z = r * iterList->q.GetColumn2();
  291.                                         Vec3 p = iterList->pos;
  292.                                         OBB obb = OBB::CreateOBB(Matrix33::CreateIdentity(), Vec3(0.05f, 0.05f, 0.05f), ZERO);
  293.                                         pAux->DrawOBB(obb, p, false, clr, eBBD_Extremes_Color_Encoded);
  294.                                         pAux->DrawLine(p, ColorF(1, 0, 0, clr.a), p + x, ColorF(1, 0, 0, clr.a));
  295.                                         pAux->DrawLine(p, ColorF(0, 1, 0, clr.a), p + y, ColorF(0, 1, 0, clr.a));
  296.                                         pAux->DrawLine(p, ColorF(0, 0, 1, clr.a), p + z, ColorF(0, 0, 1, clr.a));
  297.                                 }
  298.                                 break;
  299.                         case eOT_Arrow:
  300.                                 pAux->SetRenderFlags(flags3D);
  301.                                 pAux->DrawLine(iterList->pos - iterList->dir * iterList->radius, clr, iterList->pos + iterList->dir * iterList->radius, clr);
  302.                                 pAux->DrawCone(iterList->pos + iterList->dir * iterList->radius, iterList->dir, 0.1f * iterList->radius, 0.3f * iterList->radius, clr);
  303.                                 break;
  304.                         case eOT_Line:
  305.                                 pAux->SetRenderFlags(flags3D);
  306.                                 pAux->DrawLine(iterList->pos, clr, iterList->pos + iterList->dir, clr);
  307.                                 break;
  308.                         case eOT_Cone:
  309.                                 pAux->SetRenderFlags(flags3D);
  310.                                 pAux->DrawCone(iterList->pos, iterList->dir, iterList->radius, iterList->radius2, clr);
  311.                                 break;
  312.                         case eOT_Cylinder:
  313.                                 pAux->SetRenderFlags(flags3D);
  314.                                 pAux->DrawCylinder(iterList->pos, iterList->dir, iterList->radius, iterList->radius2, clr);
  315.                                 break;
  316.                         case eOT_AABB:
  317.                                 pAux->SetRenderFlags(flags3D);
  318.                                 pAux->DrawAABB(AABB(iterList->pos, iterList->dir), Matrix34(IDENTITY), false, clr, eBBD_Faceted);
  319.                                 break;
  320.                         case eOT_Line2D:
  321.                                 pAux->SetRenderFlags(flags2D);
  322.                                 pAux->DrawLine(iterList->pos, clr, iterList->dir, clr);
  323.                                 break;
  324.                         case eOT_Text2D:
  325.                                 {
  326.                                         float clrAry[4] = { clr.r, clr.g, clr.b, clr.a };
  327.                                         IRenderAuxText::Draw2dLabel(iterList->pos.x, iterList->pos.y, iterList->radius, clrAry, false, "%s", iterList->text.c_str());
  328.                                 }
  329.                                 break;
  330.                         case eOT_Text3D:
  331.                                 {
  332.                                         IRenderAuxText::DrawText(iterList->pos, iterList->radius, clr, eDrawText_FixedSize | eDrawText_800x600, iterList->text.c_str());
  333.                                 }
  334.                                 break;
  335.                         case eOT_Disc:
  336.                                 {
  337.                                         pAux->SetRenderFlags(flags3D);
  338.                                         vtx_idx indTriQuad[6] =
  339.                                         {
  340.                                                 0, 2, 1,
  341.                                                 0, 3, 2
  342.                                         };
  343.                                         vtx_idx indTriTri[3] =
  344.                                         {
  345.                                                 0, 1, 2
  346.                                         };
  347.  
  348.                                         int steps = (int)(10 * iterList->radius2);
  349.                                         steps = std::max(steps, 10);
  350.                                         float angStep = gf_PI2 / steps;
  351.                                         for (int i = 0; i < steps; i++)
  352.                                         {
  353.                                                 float a0 = angStep * i;
  354.                                                 float a1 = angStep * (i + 1);
  355.                                                 float c0 = cosf(a0);
  356.                                                 float c1 = cosf(a1);
  357.                                                 float s0 = sinf(a0);
  358.                                                 float s1 = sinf(a1);
  359.                                                 Vec3 pts[4];
  360.                                                 int n, n2;
  361.                                                 vtx_idx* indTri;
  362.                                                 if (iterList->radius)
  363.                                                 {
  364.                                                         n = 4;
  365.                                                         n2 = 6;
  366.                                                         pts[0] = iterList->pos + iterList->radius * Vec3(c0, s0, 0);
  367.                                                         pts[1] = iterList->pos + iterList->radius * Vec3(c1, s1, 0);
  368.                                                         pts[2] = iterList->pos + iterList->radius2 * Vec3(c1, s1, 0);
  369.                                                         pts[3] = iterList->pos + iterList->radius2 * Vec3(c0, s0, 0);
  370.                                                         indTri = indTriQuad;
  371.                                                 }
  372.                                                 else
  373.                                                 {
  374.                                                         n = 3;
  375.                                                         n2 = 3;
  376.                                                         pts[0] = iterList->pos;
  377.                                                         pts[1] = pts[0] + iterList->radius2 * Vec3(c0, s0, 0);
  378.                                                         pts[2] = pts[0] + iterList->radius2 * Vec3(c1, s1, 0);
  379.                                                         indTri = indTriTri;
  380.                                                 }
  381.                                                 pAux->DrawTriangles(pts, n, indTri, n2, clr);
  382.                                         }
  383.                                 }
  384.                                 break;
  385.                         case eOT_EntityTag:
  386.                                 {
  387.                                         UpdateTags(frameTime, *iterList);
  388.                                 }
  389.                                 break;
  390.                         }
  391.                 }
  392.                 while (!toClear.empty())
  393.                 {
  394.                         iterMap->second.erase(toClear.back());
  395.                         toClear.pop_back();
  396.                 }
  397.                 if (iterMap->second.empty())
  398.                         toClearMap.push_back(iterMap);
  399.         }
  400.         while (!toClearMap.empty())
  401.         {
  402.                 m_objects.erase(toClearMap.back());
  403.                 toClearMap.pop_back();
  404.         }
  405. }
  406.  
  407. void CPersistantDebug::PostUpdate(float frameTime)
  408. {
  409.         bool bUseUIDraw = true;
  410.  
  411.         IUIDraw* pUIDraw = CCryAction::GetCryAction()->GetIUIDraw();
  412.         if (bUseUIDraw && pUIDraw == 0)
  413.         {
  414.                 m_2DTexts.clear();
  415.                 return;
  416.         }
  417.  
  418.         IRenderer* pRenderer = gEnv->pRenderer;
  419.         const float x = bUseUIDraw ? 0.0f : pRenderer->ScaleCoordX(400.0f);
  420.  
  421.         float y = 400.0f;
  422.  
  423.         // Post update entity tags
  424.         for (MapListObj::iterator iterMap = m_objects.begin(); iterMap != m_objects.end(); ++iterMap)
  425.         {
  426.                 for (ListObj::iterator iterList = iterMap->second.begin(); iterList != iterMap->second.end(); ++iterList)
  427.                 {
  428.                         if (eOT_EntityTag == iterList->obj)
  429.                         {
  430.                                 PostUpdateTags(frameTime, *iterList);
  431.                         }
  432.                 }
  433.         }
  434.  
  435.         if (bUseUIDraw)
  436.                 pUIDraw->PreRender();
  437.  
  438.         // now draw 2D texts overlay
  439.         for (ListObjText2D::iterator iter = m_2DTexts.begin(); iter != m_2DTexts.end(); )
  440.         {
  441.                 STextObj2D& textObj = *iter;
  442.                 ColorF clr = textObj.clr;
  443.                 clr.a *= textObj.timeRemaining / textObj.totalTime;
  444.                 if (bUseUIDraw)
  445.                 {
  446.                         static const float TEXT_SPACING = 2;
  447.                         float textSize = textObj.size * 12.f;
  448.                         float sizeX, sizeY;
  449.                         const string* pTextLabel = &textObj.text;
  450.                         string localizedString;
  451.                         if (!pTextLabel->empty() && pTextLabel->at(0) == '@')
  452.                         {
  453.                                 gEnv->pSystem->GetLocalizationManager()->LocalizeString(*pTextLabel, localizedString);
  454.                                 pTextLabel = &localizedString;
  455.                         }
  456.                         pUIDraw->GetTextDim(m_pDefaultFont, &sizeX, &sizeY, textSize, textSize, pTextLabel->c_str());
  457.                         pUIDraw->DrawText(m_pDefaultFont, x, y, textSize, textSize, pTextLabel->c_str(), clr.a, clr.r, clr.g, clr.b,
  458.                                           UIDRAWHORIZONTAL_CENTER, UIDRAWVERTICAL_TOP, UIDRAWHORIZONTAL_CENTER, UIDRAWVERTICAL_TOP);
  459.                         y += sizeY + TEXT_SPACING;
  460.                 }
  461.                 else
  462.                 {
  463.                         IRenderAuxText::Draw2dLabel(x, y, textObj.size, &clr[0], true, "%s", textObj.text.c_str());
  464.                         y += 18.0f;
  465.                 }
  466.                 textObj.timeRemaining -= frameTime;
  467.                 const bool bDelete = textObj.timeRemaining <= 0.0f;
  468.                 if (bDelete)
  469.                 {
  470.                         ListObjText2D::iterator toDelete = iter;
  471.                         ++iter;
  472.                         m_2DTexts.erase(toDelete);
  473.                 }
  474.                 else
  475.                         ++iter;
  476.         }
  477.  
  478.         if (bUseUIDraw)
  479.                 pUIDraw->PostRender();
  480. }
  481.  
  482. void CPersistantDebug::OnWriteToConsole(const char* sText, bool bNewLine)
  483. {
  484.         if (sText)
  485.         {
  486.                 Add2DText(sText, 1.0f, ColorF(1.0f, 1.0f, 1.0f), 20.0f);
  487.         }
  488. }
  489.  
downloadPersistantDebug.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top