about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/engine/client/client.cpp12
-rw-r--r--src/engine/client/client.h2
-rw-r--r--src/engine/demo.h12
-rw-r--r--src/engine/shared/demo.cpp53
-rw-r--r--src/engine/shared/demo.h5
-rw-r--r--src/game/client/components/menus_demo.cpp17
-rw-r--r--src/game/client/ui.cpp5
-rw-r--r--src/game/client/ui.h1
8 files changed, 102 insertions, 5 deletions
diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp
index b115a9ac..d5da647b 100644
--- a/src/engine/client/client.cpp
+++ b/src/engine/client/client.cpp
@@ -2169,6 +2169,11 @@ void CClient::DemoRecorder_Stop()
 	m_DemoRecorder.Stop();
 }
 
+void CClient::DemoRecorder_AddDemoMarker()
+{
+	m_DemoRecorder.AddDemoMarker();
+}
+
 void CClient::Con_Record(IConsole::IResult *pResult, void *pUserData)
 {
 	CClient *pSelf = (CClient *)pUserData;
@@ -2184,6 +2189,12 @@ void CClient::Con_StopRecord(IConsole::IResult *pResult, void *pUserData)
 	pSelf->DemoRecorder_Stop();
 }
 
+void CClient::Con_AddDemoMarker(IConsole::IResult *pResult, void *pUserData)
+{
+	CClient *pSelf = (CClient *)pUserData;
+	pSelf->DemoRecorder_AddDemoMarker();
+}
+
 void CClient::ServerBrowserUpdate()
 {
 	m_ResortServerBrowser = true;
@@ -2222,6 +2233,7 @@ void CClient::RegisterCommands()
 	m_pConsole->Register("play", "r", CFGFLAG_CLIENT|CFGFLAG_STORE, Con_Play, this, "Play the file specified");
 	m_pConsole->Register("record", "?s", CFGFLAG_CLIENT, Con_Record, this, "Record to the file");
 	m_pConsole->Register("stoprecord", "", CFGFLAG_CLIENT, Con_StopRecord, this, "Stop recording");
+	m_pConsole->Register("add_demomarker", "", CFGFLAG_CLIENT, Con_AddDemoMarker, this, "Add demo timeline marker");
 	m_pConsole->Register("add_favorite", "s", CFGFLAG_CLIENT, Con_AddFavorite, this, "Add a server as a favorite");
 	m_pConsole->Register("remove_favorite", "s", CFGFLAG_CLIENT, Con_RemoveFavorite, this, "Remove a server from favorites");
 
diff --git a/src/engine/client/client.h b/src/engine/client/client.h
index 1849830c..d958b49a 100644
--- a/src/engine/client/client.h
+++ b/src/engine/client/client.h
@@ -289,6 +289,7 @@ public:
 	static void Con_Play(IConsole::IResult *pResult, void *pUserData);
 	static void Con_Record(IConsole::IResult *pResult, void *pUserData);
 	static void Con_StopRecord(IConsole::IResult *pResult, void *pUserData);
+	static void Con_AddDemoMarker(IConsole::IResult *pResult, void *pUserData);
 	static void ConchainServerBrowserUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
 
 	void RegisterCommands();
@@ -297,6 +298,7 @@ public:
 	void DemoRecorder_Start(const char *pFilename, bool WithTimestamp);
 	void DemoRecorder_HandleAutoStart();
 	void DemoRecorder_Stop();
+	void DemoRecorder_AddDemoMarker();
 
 	void AutoScreenshot_Start();
 	void AutoScreenshot_Cleanup();
diff --git a/src/engine/demo.h b/src/engine/demo.h
index a9e4f700..7b7365c7 100644
--- a/src/engine/demo.h
+++ b/src/engine/demo.h
@@ -5,6 +5,11 @@
 
 #include "kernel.h"
 
+enum
+{
+	MAX_TIMELINE_MARKERS=64
+};
+
 struct CDemoHeader
 {
 	unsigned char m_aMarker[7];
@@ -16,6 +21,8 @@ struct CDemoHeader
 	char m_aType[8];
 	char m_aLength[4];
 	char m_aTimestamp[20];
+	char m_aNumTimelineMarkers[4];
+	char m_aTimelineMarkers[MAX_TIMELINE_MARKERS][4];
 };
 
 class IDemoPlayer : public IInterface
@@ -31,6 +38,9 @@ public:
 		int m_FirstTick;
 		int m_CurrentTick;
 		int m_LastTick;
+
+		int m_NumTimelineMarkers;
+		int m_aTimelineMarkers[MAX_TIMELINE_MARKERS];
 	};
 
 	enum
@@ -42,7 +52,7 @@ public:
 
 	~IDemoPlayer() {}
 	virtual void SetSpeed(float Speed) = 0;
-	virtual int SetPos(float Precent) = 0;
+	virtual int SetPos(float Percent) = 0;
 	virtual void Pause() = 0;
 	virtual void Unpause() = 0;
 	virtual const CInfo *BaseInfo() const = 0;
diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp
index 2bd7c28a..37c82cce 100644
--- a/src/engine/shared/demo.cpp
+++ b/src/engine/shared/demo.cpp
@@ -13,8 +13,9 @@
 #include "snapshot.h"
 
 static const unsigned char gs_aHeaderMarker[7] = {'T', 'W', 'D', 'E', 'M', 'O', 0};
-static const unsigned char gs_ActVersion = 3;
+static const unsigned char gs_ActVersion = 4;
 static const int gs_LengthOffset = 152;
+static const int gs_NumMarkersOffset = 176;
 
 
 CDemoRecorder::CDemoRecorder(class CSnapshotDelta *pSnapshotDelta)
@@ -89,6 +90,8 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con
 	str_copy(Header.m_aType, pType, sizeof(Header.m_aType));
 	// Header.m_Length - add this on stop
 	str_timestamp(Header.m_aTimestamp, sizeof(Header.m_aTimestamp));
+	// Header.m_aNumTimelineMarkers - add this on stop
+	// Header.m_aTimelineMarkers - add this on stop
 	io_write(DemoFile, &Header, sizeof(Header));
 
 	// write map data
@@ -105,6 +108,7 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con
 	m_LastKeyFrame = -1;
 	m_LastTickMarker = -1;
 	m_FirstTick = -1;
+	m_NumTimelineMarkers = 0;
 
 	char aBuf[256];
 	str_format(aBuf, sizeof(aBuf), "Recording to '%s'", pFilename);
@@ -266,6 +270,25 @@ int CDemoRecorder::Stop()
 	aLength[3] = (DemoLength)&0xff;
 	io_write(m_File, aLength, sizeof(aLength));
 
+	// add the timeline markers to the header
+	io_seek(m_File, gs_NumMarkersOffset, IOSEEK_START);
+	char aNumMarkers[4];
+	aNumMarkers[0] = (m_NumTimelineMarkers>>24)&0xff;
+	aNumMarkers[1] = (m_NumTimelineMarkers>>16)&0xff;
+	aNumMarkers[2] = (m_NumTimelineMarkers>>8)&0xff;
+	aNumMarkers[3] = (m_NumTimelineMarkers)&0xff;
+	io_write(m_File, aNumMarkers, sizeof(aNumMarkers));
+	for(int i = 0; i < m_NumTimelineMarkers; i++)
+	{
+		int Marker = m_aTimelineMarkers[i];
+		char aMarker[4];
+		aMarker[0] = (Marker>>24)&0xff;
+		aMarker[1] = (Marker>>16)&0xff;
+		aMarker[2] = (Marker>>8)&0xff;
+		aMarker[3] = (Marker)&0xff;
+		io_write(m_File, aMarker, sizeof(aMarker));
+	}
+
 	io_close(m_File);
 	m_File = 0;
 	m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Stopped recording");
@@ -273,6 +296,24 @@ int CDemoRecorder::Stop()
 	return 0;
 }
 
+void CDemoRecorder::AddDemoMarker()
+{
+	if(m_LastTickMarker < 0 || m_NumTimelineMarkers >= MAX_TIMELINE_MARKERS)
+		return;
+
+	// not more than 1 marker in a second
+	if(m_NumTimelineMarkers > 0)
+	{
+		int Diff = m_LastTickMarker - m_aTimelineMarkers[m_NumTimelineMarkers-1];
+		if(Diff < SERVER_TICK_SPEED*1.0f)
+			return;
+	}
+
+	m_aTimelineMarkers[m_NumTimelineMarkers++] = m_LastTickMarker;
+
+	m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Added timeline marker");
+}
+
 
 
 CDemoPlayer::CDemoPlayer(class CSnapshotDelta *pSnapshotDelta)
@@ -622,6 +663,16 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const
 		mem_free(pMapData);
 	}
 
+	// get timeline markers
+	int Num = ((m_Info.m_Header.m_aNumTimelineMarkers[0]<<24)&0xFF000000) | ((m_Info.m_Header.m_aNumTimelineMarkers[1]<<16)&0xFF0000) |
+				((m_Info.m_Header.m_aNumTimelineMarkers[2]<<8)&0xFF00) | (m_Info.m_Header.m_aNumTimelineMarkers[3]&0xFF);
+	m_Info.m_Info.m_NumTimelineMarkers = Num;
+	for(int i = 0; i < Num && i < MAX_TIMELINE_MARKERS; i++)
+	{
+		char *pTimelineMarker = m_Info.m_Header.m_aTimelineMarkers[i];
+		m_Info.m_Info.m_aTimelineMarkers[i] = ((pTimelineMarker[0]<<24)&0xFF000000) | ((pTimelineMarker[1]<<16)&0xFF0000) |
+												((pTimelineMarker[2]<<8)&0xFF00) | (pTimelineMarker[3]&0xFF);
+	}
 
 	// scan the file for interessting points
 	ScanFile();
diff --git a/src/engine/shared/demo.h b/src/engine/shared/demo.h
index f4ac5685..760e7256 100644
--- a/src/engine/shared/demo.h
+++ b/src/engine/shared/demo.h
@@ -17,6 +17,8 @@ class CDemoRecorder : public IDemoRecorder
 	int m_FirstTick;
 	unsigned char m_aLastSnapshotData[CSnapshot::MAX_SIZE];
 	class CSnapshotDelta *m_pSnapshotDelta;
+	int m_NumTimelineMarkers;
+	int m_aTimelineMarkers[MAX_TIMELINE_MARKERS];
 
 	void WriteTickMarker(int Tick, int Keyframe);
 	void Write(int Type, const void *pData, int Size);
@@ -25,6 +27,7 @@ public:
 
 	int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, unsigned MapCrc, const char *pType);
 	int Stop();
+	void AddDemoMarker();
 
 	void RecordSnapshot(int Tick, const void *pData, int Size);
 	void RecordMessage(const void *pData, int Size);
@@ -108,7 +111,7 @@ public:
 	void Unpause();
 	int Stop();
 	void SetSpeed(float Speed);
-	int SetPos(float Precent);
+	int SetPos(float Percent);
 	const CInfo *BaseInfo() const { return &m_Info.m_Info; }
 	void GetDemoName(char *pBuffer, int BufferSize) const;
 	bool GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, CDemoHeader *pDemoHeader) const;
diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp
index ec3e648c..40a9e5b5 100644
--- a/src/game/client/components/menus_demo.cpp
+++ b/src/game/client/components/menus_demo.cpp
@@ -86,15 +86,28 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
 		void *id = &s_SeekBarID;
 		char aBuffer[128];
 
+		// draw seek bar
 		RenderTools()->DrawUIRect(&SeekBar, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 5.0f);
 
+		// draw filled bar
 		float Amount = CurrentTick/(float)TotalTicks;
-
 		CUIRect FilledBar = SeekBar;
 		FilledBar.w = 10.0f + (FilledBar.w-10.0f)*Amount;
-
 		RenderTools()->DrawUIRect(&FilledBar, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 5.0f);
 
+		// draw markers
+		for(int i = 0; i < pInfo->m_NumTimelineMarkers; i++)
+		{
+			float Ratio = (pInfo->m_aTimelineMarkers[i]-pInfo->m_FirstTick) / (float)TotalTicks;
+			Graphics()->TextureSet(-1);
+			Graphics()->QuadsBegin();
+			Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+			IGraphics::CQuadItem QuadItem(SeekBar.x + (SeekBar.w-10.0f)*Ratio, SeekBar.y, UI()->PixelSize(), SeekBar.h);
+			Graphics()->QuadsDrawTL(&QuadItem, 1);
+			Graphics()->QuadsEnd();
+		}
+
+		// draw time
 		str_format(aBuffer, sizeof(aBuffer), "%d:%02d / %d:%02d",
 			CurrentTick/SERVER_TICK_SPEED/60, (CurrentTick/SERVER_TICK_SPEED)%60,
 			TotalTicks/SERVER_TICK_SPEED/60, (TotalTicks/SERVER_TICK_SPEED)%60);
diff --git a/src/game/client/ui.cpp b/src/game/client/ui.cpp
index 00a30c15..c5219575 100644
--- a/src/game/client/ui.cpp
+++ b/src/game/client/ui.cpp
@@ -74,6 +74,11 @@ CUIRect *CUI::Screen()
 	return &m_Screen;
 }
 
+float CUI::PixelSize()
+{
+	return Screen()->w/Graphics()->ScreenWidth();
+}
+
 void CUI::SetScale(float s)
 {
 	g_Config.m_UiScale = (int)(s*100.0f);
diff --git a/src/game/client/ui.h b/src/game/client/ui.h
index 7cd78d6f..daba5d51 100644
--- a/src/game/client/ui.h
+++ b/src/game/client/ui.h
@@ -82,6 +82,7 @@ public:
 	void ConvertMouseMove(float *x, float *y);
 
 	CUIRect *Screen();
+	float PixelSize();
 	void ClipEnable(const CUIRect *pRect);
 	void ClipDisable();