imgui_impl_marmalade.cpp
Go to the documentation of this file.
1 // dear imgui: Renderer + Platform Binding for Marmalade + IwGx
2 // Marmalade code: Copyright (C) 2015 by Giovanni Zito (this file is part of Dear ImGui)
3 
4 // Implemented features:
5 // [X] Renderer: User texture binding. Use 'CIwTexture*' as ImTextureID. Read the FAQ about ImTextureID!
6 // Missing features:
7 // [ ] Renderer: Clipping rectangles are not honored.
8 
9 // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
10 // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
11 // https://github.com/ocornut/imgui
12 
13 // CHANGELOG
14 // (minor and older changes stripped away, please see git history for details)
15 // 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
16 // 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
17 // 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
18 // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_Marmalade_RenderDrawData() in the .h file so you can call it yourself.
19 // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
20 // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
21 
22 #include "imgui.h"
23 #include "imgui_impl_marmalade.h"
24 
25 #include <s3eClipboard.h>
26 #include <s3ePointer.h>
27 #include <s3eKeyboard.h>
28 #include <IwTexture.h>
29 #include <IwGx.h>
30 
31 // Data
32 static double g_Time = 0.0f;
33 static bool g_MousePressed[3] = { false, false, false };
34 static CIwTexture* g_FontTexture = NULL;
35 static char* g_ClipboardText = NULL;
36 static bool g_osdKeyboardEnabled = false;
37 
38 // use this setting to scale the interface - e.g. on device you could use 2 or 3 scale factor
39 static ImVec2 g_RenderScale = ImVec2(1.0f,1.0f);
40 
41 // Render function.
42 // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
44 {
45  // Avoid rendering when minimized
46  if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
47  return;
48 
49  // Render command lists
50  for (int n = 0; n < draw_data->CmdListsCount; n++)
51  {
52  const ImDrawList* cmd_list = draw_data->CmdLists[n];
53  const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
54  const int nVert = cmd_list->VtxBuffer.Size;
55  CIwFVec2* pVertStream = IW_GX_ALLOC(CIwFVec2, nVert);
56  CIwFVec2* pUVStream = IW_GX_ALLOC(CIwFVec2, nVert);
57  CIwColour* pColStream = IW_GX_ALLOC(CIwColour, nVert);
58 
59  for (int i = 0; i < nVert; i++)
60  {
61  // FIXME-OPT: optimize multiplication on GPU using vertex shader/projection matrix.
62  pVertStream[i].x = cmd_list->VtxBuffer[i].pos.x * g_RenderScale.x;
63  pVertStream[i].y = cmd_list->VtxBuffer[i].pos.y * g_RenderScale.y;
64  pUVStream[i].x = cmd_list->VtxBuffer[i].uv.x;
65  pUVStream[i].y = cmd_list->VtxBuffer[i].uv.y;
66  pColStream[i] = cmd_list->VtxBuffer[i].col;
67  }
68 
69  IwGxSetVertStreamScreenSpace(pVertStream, nVert);
70  IwGxSetUVStream(pUVStream);
71  IwGxSetColStream(pColStream, nVert);
72  IwGxSetNormStream(0);
73 
74  for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
75  {
76  const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
77  if (pcmd->UserCallback)
78  {
79  pcmd->UserCallback(cmd_list, pcmd);
80  }
81  else
82  {
83  // FIXME: Not honoring ClipRect fields.
84  CIwMaterial* pCurrentMaterial = IW_GX_ALLOC_MATERIAL();
85  pCurrentMaterial->SetShadeMode(CIwMaterial::SHADE_FLAT);
86  pCurrentMaterial->SetCullMode(CIwMaterial::CULL_NONE);
87  pCurrentMaterial->SetFiltering(false);
88  pCurrentMaterial->SetAlphaMode(CIwMaterial::ALPHA_BLEND);
89  pCurrentMaterial->SetDepthWriteMode(CIwMaterial::DEPTH_WRITE_NORMAL);
90  pCurrentMaterial->SetAlphaTestMode(CIwMaterial::ALPHATEST_DISABLED);
91  pCurrentMaterial->SetTexture((CIwTexture*)pcmd->TextureId);
92  IwGxSetMaterial(pCurrentMaterial);
93  IwGxDrawPrims(IW_GX_TRI_LIST, (uint16*)idx_buffer, pcmd->ElemCount);
94  }
95  idx_buffer += pcmd->ElemCount;
96  }
97  IwGxFlush();
98  }
99 
100  // TODO: restore modified state (i.e. mvp matrix)
101 }
102 
103 static const char* ImGui_Marmalade_GetClipboardText(void* /*user_data*/)
104 {
105  if (!s3eClipboardAvailable())
106  return NULL;
107 
108  if (int size = s3eClipboardGetText(NULL, 0))
109  {
110  if (g_ClipboardText)
111  delete[] g_ClipboardText;
112  g_ClipboardText = new char[size];
113  g_ClipboardText[0] = '\0';
114  s3eClipboardGetText(g_ClipboardText, size);
115  }
116 
117  return g_ClipboardText;
118 }
119 
120 static void ImGui_Marmalade_SetClipboardText(void* /*user_data*/, const char* text)
121 {
122  if (s3eClipboardAvailable())
123  s3eClipboardSetText(text);
124 }
125 
126 int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_data)
127 {
128  // pEvent->m_Button is of type s3ePointerButton and indicates which mouse
129  // button was pressed. For touchscreen this should always have the value
130  // S3E_POINTER_BUTTON_SELECT
131  s3ePointerEvent* pEvent = (s3ePointerEvent*)system_data;
132 
133  if (pEvent->m_Pressed == 1)
134  {
135  if (pEvent->m_Button == S3E_POINTER_BUTTON_LEFTMOUSE)
136  g_MousePressed[0] = true;
137  if (pEvent->m_Button == S3E_POINTER_BUTTON_RIGHTMOUSE)
138  g_MousePressed[1] = true;
139  if (pEvent->m_Button == S3E_POINTER_BUTTON_MIDDLEMOUSE)
140  g_MousePressed[2] = true;
141  if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELUP)
142  io.MouseWheel += pEvent->m_y;
143  if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELDOWN)
144  io.MouseWheel += pEvent->m_y;
145  }
146 
147  return 0;
148 }
149 
150 int32 ImGui_Marmalade_KeyCallback(void* system_data, void* user_data)
151 {
152  ImGuiIO& io = ImGui::GetIO();
153  s3eKeyboardEvent* e = (s3eKeyboardEvent*)system_data;
154  if (e->m_Pressed == 1)
155  io.KeysDown[e->m_Key] = true;
156  if (e->m_Pressed == 0)
157  io.KeysDown[e->m_Key] = false;
158 
159  io.KeyCtrl = s3eKeyboardGetState(s3eKeyLeftControl) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightControl) == S3E_KEY_STATE_DOWN;
160  io.KeyShift = s3eKeyboardGetState(s3eKeyLeftShift) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightShift) == S3E_KEY_STATE_DOWN;
161  io.KeyAlt = s3eKeyboardGetState(s3eKeyLeftAlt) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightAlt) == S3E_KEY_STATE_DOWN;
162  io.KeySuper = s3eKeyboardGetState(s3eKeyLeftWindows) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightWindows) == S3E_KEY_STATE_DOWN;
163 
164  return 0;
165 }
166 
167 int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data)
168 {
169  ImGuiIO& io = ImGui::GetIO();
170  s3eKeyboardCharEvent* e = (s3eKeyboardCharEvent*)system_data;
171  io.AddInputCharacter((unsigned int)e->m_Char);
172 
173  return 0;
174 }
175 
177 {
178  // Build texture atlas
179  ImGuiIO& io = ImGui::GetIO();
180  unsigned char* pixels;
181  int width, height;
183 
184  // Upload texture to graphics system
185  g_FontTexture = new CIwTexture();
186  g_FontTexture->SetModifiable(true);
187  CIwImage& image = g_FontTexture->GetImage();
188  image.SetFormat(CIwImage::ARGB_8888);
189  image.SetWidth(width);
190  image.SetHeight(height);
191  image.SetBuffers(); // allocates and own buffers
192  image.ReadTexels(pixels);
193  g_FontTexture->SetMipMapping(false);
194  g_FontTexture->SetFiltering(false);
195  g_FontTexture->Upload();
196 
197  // Store our identifier
199 
200  return true;
201 }
202 
204 {
205  if (g_ClipboardText)
206  {
207  delete[] g_ClipboardText;
209  }
210 
211  if (g_FontTexture)
212  {
213  delete g_FontTexture;
214  ImGui::GetIO().Fonts->TexID = 0;
216  }
217 }
218 
219 bool ImGui_Marmalade_Init(bool install_callbacks)
220 {
221  ImGuiIO& io = ImGui::GetIO();
222  io.BackendPlatformName = io.BackendRendererName = "imgui_impl_marmalade";
223 
224  io.KeyMap[ImGuiKey_Tab] = s3eKeyTab; // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
225  io.KeyMap[ImGuiKey_LeftArrow] = s3eKeyLeft;
226  io.KeyMap[ImGuiKey_RightArrow] = s3eKeyRight;
227  io.KeyMap[ImGuiKey_UpArrow] = s3eKeyUp;
228  io.KeyMap[ImGuiKey_DownArrow] = s3eKeyDown;
229  io.KeyMap[ImGuiKey_PageUp] = s3eKeyPageUp;
230  io.KeyMap[ImGuiKey_PageDown] = s3eKeyPageDown;
231  io.KeyMap[ImGuiKey_Home] = s3eKeyHome;
232  io.KeyMap[ImGuiKey_End] = s3eKeyEnd;
233  io.KeyMap[ImGuiKey_Insert] = s3eKeyInsert;
234  io.KeyMap[ImGuiKey_Delete] = s3eKeyDelete;
235  io.KeyMap[ImGuiKey_Backspace] = s3eKeyBackspace;
236  io.KeyMap[ImGuiKey_Space] = s3eKeySpace;
237  io.KeyMap[ImGuiKey_Enter] = s3eKeyEnter;
238  io.KeyMap[ImGuiKey_Escape] = s3eKeyEsc;
239  io.KeyMap[ImGuiKey_KeyPadEnter] = s3eKeyNumPadEnter;
240  io.KeyMap[ImGuiKey_A] = s3eKeyA;
241  io.KeyMap[ImGuiKey_C] = s3eKeyC;
242  io.KeyMap[ImGuiKey_V] = s3eKeyV;
243  io.KeyMap[ImGuiKey_X] = s3eKeyX;
244  io.KeyMap[ImGuiKey_Y] = s3eKeyY;
245  io.KeyMap[ImGuiKey_Z] = s3eKeyZ;
246 
249 
250  if (install_callbacks)
251  {
252  s3ePointerRegister(S3E_POINTER_BUTTON_EVENT, ImGui_Marmalade_PointerButtonEventCallback, 0);
253  s3eKeyboardRegister(S3E_KEYBOARD_KEY_EVENT, ImGui_Marmalade_KeyCallback, 0);
254  s3eKeyboardRegister(S3E_KEYBOARD_CHAR_EVENT, ImGui_Marmalade_CharCallback, 0);
255  }
256 
257  return true;
258 }
259 
261 {
263 }
264 
266 {
267  if (!g_FontTexture)
269 
270  ImGuiIO& io = ImGui::GetIO();
271 
272  // Setup display size (every frame to accommodate for window resizing)
273  int w = IwGxGetScreenWidth(), h = IwGxGetScreenHeight();
274  io.DisplaySize = ImVec2((float)w, (float)h);
275  // For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui.
276  io.DisplayFramebufferScale = g_scale;
277 
278  // Setup time step
279  double current_time = s3eTimerGetUST() / 1000.0f;
280  io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);
281  g_Time = current_time;
282 
283  double mouse_x, mouse_y;
284  mouse_x = s3ePointerGetX();
285  mouse_y = s3ePointerGetY();
286  io.MousePos = ImVec2((float)mouse_x/g_scale.x, (float)mouse_y/g_scale.y); // Mouse position (set to -FLT_MAX,-FLT_MAX if no mouse / on another screen, etc.)
287 
288  for (int i = 0; i < 3; i++)
289  {
290  io.MouseDown[i] = g_MousePressed[i] || s3ePointerGetState((s3ePointerButton)i) != S3E_POINTER_STATE_UP; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
291  g_MousePressed[i] = false;
292  }
293 
294  // TODO: Hide OS mouse cursor if ImGui is drawing it
295  // s3ePointerSetInt(S3E_POINTER_HIDE_CURSOR,(io.MouseDrawCursor ? 0 : 1));
296 
297  // Show/hide OSD keyboard
298  if (io.WantTextInput)
299  {
300  // Some text input widget is active?
302  {
303  g_osdKeyboardEnabled = true;
304  s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 1); // show OSD keyboard
305  }
306  }
307  else
308  {
309  // No text input widget is active
311  {
312  g_osdKeyboardEnabled = false;
313  s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 0); // hide OSD keyboard
314  }
315  }
316 }
ImGuiIO::KeyMap
int KeyMap[ImGuiKey_COUNT]
Definition: imgui.h:1430
ImGuiKey_Z
@ ImGuiKey_Z
Definition: imgui.h:1008
g_ClipboardText
static char * g_ClipboardText
Definition: imgui_impl_marmalade.cpp:35
g_osdKeyboardEnabled
static bool g_osdKeyboardEnabled
Definition: imgui_impl_marmalade.cpp:36
ImGuiIO::WantTextInput
bool WantTextInput
Definition: imgui.h:1508
ImDrawIdx
unsigned short ImDrawIdx
Definition: imgui.h:1888
ImGuiIO::KeySuper
bool KeySuper
Definition: imgui.h:1492
ImGuiIO::KeyCtrl
bool KeyCtrl
Definition: imgui.h:1489
height
GLint GLsizei GLsizei height
Definition: glcorearb.h:2768
g_Time
static double g_Time
Definition: imgui_impl_marmalade.cpp:32
ImGui_Marmalade_SetClipboardText
static void ImGui_Marmalade_SetClipboardText(void *, const char *text)
Definition: imgui_impl_marmalade.cpp:120
ImGuiIO::Fonts
ImFontAtlas * Fonts
Definition: imgui.h:1435
ImDrawList::IdxBuffer
ImVector< ImDrawIdx > IdxBuffer
Definition: imgui.h:1965
ImFontAtlas::TexID
ImTextureID TexID
Definition: imgui.h:2247
ImGuiKey_PageUp
@ ImGuiKey_PageUp
Definition: imgui.h:992
ImDrawData::CmdListsCount
int CmdListsCount
Definition: imgui.h:2072
ImGui_Marmalade_InvalidateDeviceObjects
void ImGui_Marmalade_InvalidateDeviceObjects()
Definition: imgui_impl_marmalade.cpp:203
NULL
NULL
Definition: test_security_zap.cpp:405
g_RenderScale
static ImVec2 g_RenderScale
Definition: imgui_impl_marmalade.cpp:39
ImGui_Marmalade_CreateDeviceObjects
bool ImGui_Marmalade_CreateDeviceObjects()
Definition: imgui_impl_marmalade.cpp:176
ImGui_Marmalade_PointerButtonEventCallback
int32 ImGui_Marmalade_PointerButtonEventCallback(void *system_data, void *user_data)
Definition: imgui_impl_marmalade.cpp:126
ImGuiIO::KeyShift
bool KeyShift
Definition: imgui.h:1490
ImGuiIO::DisplayFramebufferScale
ImVec2 DisplayFramebufferScale
Definition: imgui.h:1439
g_FontTexture
static CIwTexture * g_FontTexture
Definition: imgui_impl_marmalade.cpp:34
ImDrawData::CmdLists
ImDrawList ** CmdLists
Definition: imgui.h:2071
ImGuiKey_Enter
@ ImGuiKey_Enter
Definition: imgui.h:1000
ImGuiKey_Delete
@ ImGuiKey_Delete
Definition: imgui.h:997
ImGui_Marmalade_NewFrame
void ImGui_Marmalade_NewFrame()
Definition: imgui_impl_marmalade.cpp:265
ImGuiKey_X
@ ImGuiKey_X
Definition: imgui.h:1006
ImGui_Marmalade_RenderDrawData
void ImGui_Marmalade_RenderDrawData(ImDrawData *draw_data)
Definition: imgui_impl_marmalade.cpp:43
ImGui_Marmalade_Init
bool ImGui_Marmalade_Init(bool install_callbacks)
Definition: imgui_impl_marmalade.cpp:219
ImDrawList
Definition: imgui.h:1961
ImTextureID
void * ImTextureID
Definition: imgui.h:172
ImGuiKey_RightArrow
@ ImGuiKey_RightArrow
Definition: imgui.h:989
imgui.h
ImGuiKey_Space
@ ImGuiKey_Space
Definition: imgui.h:999
ImGuiIO::GetClipboardTextFn
const char *(* GetClipboardTextFn)(void *user_data)
Definition: imgui.h:1463
ImVec2
Definition: imgui.h:208
ImGuiKey_End
@ ImGuiKey_End
Definition: imgui.h:995
ImGuiIO::KeyAlt
bool KeyAlt
Definition: imgui.h:1491
ImGui::GetIO
IMGUI_API ImGuiIO & GetIO()
Definition: imgui.cpp:3286
ImGuiIO::AddInputCharacter
IMGUI_API void AddInputCharacter(unsigned int c)
Definition: imgui.cpp:1130
ImDrawList::CmdBuffer
ImVector< ImDrawCmd > CmdBuffer
Definition: imgui.h:1964
ImDrawCmd
Definition: imgui.h:1871
ImDrawCmd::TextureId
ImTextureID TextureId
Definition: imgui.h:1875
ImGuiKey_A
@ ImGuiKey_A
Definition: imgui.h:1003
ImGuiKey_Home
@ ImGuiKey_Home
Definition: imgui.h:994
ImDrawCmd::UserCallback
ImDrawCallback UserCallback
Definition: imgui.h:1878
imgui_impl_marmalade.h
google::protobuf::int32
int32_t int32
Definition: protobuf/src/google/protobuf/stubs/port.h:150
ImGuiIO::MouseDown
bool MouseDown[5]
Definition: imgui.h:1486
ImVector::Data
T * Data
Definition: imgui.h:1305
ImGuiKey_Y
@ ImGuiKey_Y
Definition: imgui.h:1007
ImGuiKey_DownArrow
@ ImGuiKey_DownArrow
Definition: imgui.h:991
google::protobuf::uint16
uint16_t uint16
Definition: protobuf/src/google/protobuf/stubs/port.h:154
ImDrawData
Definition: imgui.h:2068
ImVector::Size
int Size
Definition: imgui.h:1303
ImVec2::x
float x
Definition: imgui.h:210
ImGuiKey_KeyPadEnter
@ ImGuiKey_KeyPadEnter
Definition: imgui.h:1002
size
#define size
Definition: glcorearb.h:2944
ImGuiKey_LeftArrow
@ ImGuiKey_LeftArrow
Definition: imgui.h:988
g_MousePressed
static bool g_MousePressed[3]
Definition: imgui_impl_marmalade.cpp:33
ImGuiKey_PageDown
@ ImGuiKey_PageDown
Definition: imgui.h:993
n
GLdouble n
Definition: glcorearb.h:4153
ImGuiKey_C
@ ImGuiKey_C
Definition: imgui.h:1004
ImDrawList::VtxBuffer
ImVector< ImDrawVert > VtxBuffer
Definition: imgui.h:1966
i
int i
Definition: gmock-matchers_test.cc:764
ImGuiKey_Escape
@ ImGuiKey_Escape
Definition: imgui.h:1001
ImGuiIO::BackendPlatformName
const char * BackendPlatformName
Definition: imgui.h:1455
ImGuiIO::MousePos
ImVec2 MousePos
Definition: imgui.h:1485
ImGui_Marmalade_CharCallback
int32 ImGui_Marmalade_CharCallback(void *system_data, void *user_data)
Definition: imgui_impl_marmalade.cpp:167
ImGuiIO::DisplaySize
ImVec2 DisplaySize
Definition: imgui.h:1422
size
GLsizeiptr size
Definition: glcorearb.h:2943
ImGuiIO::BackendRendererName
const char * BackendRendererName
Definition: imgui.h:1456
ImGui_Marmalade_GetClipboardText
static const char * ImGui_Marmalade_GetClipboardText(void *)
Definition: imgui_impl_marmalade.cpp:103
ImGui_Marmalade_Shutdown
void ImGui_Marmalade_Shutdown()
Definition: imgui_impl_marmalade.cpp:260
ImGuiIO
Definition: imgui.h:1414
ImGuiKey_Backspace
@ ImGuiKey_Backspace
Definition: imgui.h:998
ImGuiIO::KeysDown
bool KeysDown[512]
Definition: imgui.h:1493
ImGuiKey_UpArrow
@ ImGuiKey_UpArrow
Definition: imgui.h:990
ImGui_Marmalade_KeyCallback
int32 ImGui_Marmalade_KeyCallback(void *system_data, void *user_data)
Definition: imgui_impl_marmalade.cpp:150
ImDrawData::DisplaySize
ImVec2 DisplaySize
Definition: imgui.h:2076
f
GLfloat f
Definition: glcorearb.h:3964
ImGuiKey_Insert
@ ImGuiKey_Insert
Definition: imgui.h:996
pixels
GLint GLint GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: glcorearb.h:2773
w
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:3126
ImGuiIO::DeltaTime
float DeltaTime
Definition: imgui.h:1423
ImGuiKey_Tab
@ ImGuiKey_Tab
Definition: imgui.h:987
h
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:4147
ImVec2::y
float y
Definition: imgui.h:210
width
GLint GLsizei width
Definition: glcorearb.h:2768
ImGuiIO::SetClipboardTextFn
void(* SetClipboardTextFn)(void *user_data, const char *text)
Definition: imgui.h:1464
ImDrawCmd::ElemCount
unsigned int ElemCount
Definition: imgui.h:1873
ImFontAtlas::GetTexDataAsRGBA32
IMGUI_API void GetTexDataAsRGBA32(unsigned char **out_pixels, int *out_width, int *out_height, int *out_bytes_per_pixel=NULL)
Definition: imgui_draw.cpp:1679
ImGuiKey_V
@ ImGuiKey_V
Definition: imgui.h:1005


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:54