2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
32 // included for image uploading for player stat graph
33 #include "../renderer/Image.h"
35 #include "DeviceContext.h"
37 #include "UserInterfaceLocal.h"
38 #include "MarkerWindow.h"
41 void idMarkerWindow::CommonInit() {
51 idMarkerWindow::idMarkerWindow(idDeviceContext *d, idUserInterfaceLocal *g) : idWindow(d, g) {
57 idMarkerWindow::idMarkerWindow(idUserInterfaceLocal *g) : idWindow(g) {
62 idMarkerWindow::~idMarkerWindow() {
65 bool idMarkerWindow::ParseInternalVar(const char *_name, idParser *src) {
66 if (idStr::Icmp(_name, "markerMat") == 0) {
68 ParseString(src, str);
69 markerMat = declManager->FindMaterial(str);
70 markerMat->SetSort( SS_GUI );
73 if (idStr::Icmp(_name, "markerStop") == 0) {
75 ParseString(src, str);
76 markerStop = declManager->FindMaterial(str);
77 markerStop->SetSort( SS_GUI );
80 if (idStr::Icmp(_name, "markerColor") == 0) {
81 ParseVec4(src, markerColor);
84 return idWindow::ParseInternalVar(_name, src);
87 idWinVar *idMarkerWindow::GetWinVarByName(const char *_name, bool fixup) {
88 return idWindow::GetWinVarByName(_name, fixup);
91 const char *idMarkerWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) {
93 if (!(event->evType == SE_KEY && event->evValue2)) {
97 int key = event->evValue;
98 if (event->evValue2 && key == K_MOUSE1) {
99 gui->GetDesktop()->SetChildWinVarVal("markerText", "text", "");
101 int c = markerTimes.Num();
103 for (i = 0; i < c; i++) {
104 markerData_t &md = markerTimes[i];
105 if (md.rect.Contains(gui->CursorX(), gui->CursorY())) {
107 gui->SetStateInt( "currentMarker", md.time );
109 gui->GetDesktop()->SetChildWinVarVal("markerText", "text", va("Marker set at %.2i:%.2i", md.time / 60 / 60, (md.time / 60) % 60));
110 gui->GetDesktop()->SetChildWinVarVal("markerText", "visible", "1");
111 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "matcolor", "1 1 1 1");
112 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "text", "");
113 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "background", md.mat->GetName());
118 // no marker selected;
120 gui->SetStateInt( "currentMarker", currentTime );
121 stopTime = currentTime;
122 gui->GetDesktop()->SetChildWinVarVal("markerText", "text", va("Marker set at %.2i:%.2i", currentTime / 60 / 60, (currentTime / 60) % 60));
123 gui->GetDesktop()->SetChildWinVarVal("markerText", "visible", "1");
124 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "matcolor", "0 0 0 0");
125 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "text", "No Preview");
127 float pct = gui->State().GetFloat( "loadPct" );
128 int len = gui->State().GetInt( "loadLength" );
129 if (stopTime > len * pct) {
130 return "cmdDemoGotoMarker";
132 } else if (key == K_MOUSE2) {
134 gui->GetDesktop()->SetChildWinVarVal("markerText", "text", "");
135 gui->SetStateInt( "currentMarker", -1 );
136 return "cmdDemoGotoMarker";
137 } else if (key == K_SPACE) {
138 return "cmdDemoPauseFrame";
144 void idMarkerWindow::PostParse() {
145 idWindow::PostParse();
148 static const int HEALTH_MAX = 100;
149 static const int COMBAT_MAX = 100;
150 static const int RATE_MAX = 125;
151 static const int STAMINA_MAX = 12;
152 void idMarkerWindow::Draw(int time, float x, float y) {
154 idRectangle r = clientRect;
155 int len = gui->State().GetInt( "loadLength" );
160 int c = markerTimes.Num();
162 for (int i = 0; i < c; i++) {
163 markerData_t &md = markerTimes[i];
164 if (md.rect.w == 0) {
165 md.rect.x = (r.x + r.w * ((float)md.time / len)) - 8;
166 md.rect.y = r.y + r.h - 20;
170 dc->DrawMaterial(md.rect.x, md.rect.y, md.rect.w, md.rect.h, markerMat, markerColor);
176 if (r.w > 0 && r.Contains(gui->CursorX(), gui->CursorY())) {
177 pct = (gui->CursorX() - r.x) / r.w;
178 currentTime = len * pct;
179 r.x = (gui->CursorX() > r.x + r.w - 40) ? gui->CursorX() - 40 : gui->CursorX();
180 r.y = gui->CursorY() - 15;
183 dc->DrawText(va("%.2i:%.2i", currentTime / 60 / 60, (currentTime / 60) % 60), 0.25, 0, idDeviceContext::colorWhite, r, false);
186 if (stopTime >= 0 && markerStop) {
188 r.y += (r.h - 32) / 2;
189 pct = (float)stopTime / len;
190 r.x += (r.w * pct) - 16;
191 idVec4 color(1, 1, 1, 0.65f);
192 dc->DrawMaterial(r.x, r.y, 32, 32, markerStop, color);
199 const char *idMarkerWindow::RouteMouseCoords(float xd, float yd) {
200 const char * ret = idWindow::RouteMouseCoords(xd, yd);
202 int i, c = markerTimes.Num();
203 int len = gui->State().GetInt( "loadLength" );
207 for (i = 0; i < c; i++) {
208 markerData_t &md = markerTimes[i];
209 if (md.rect.Contains(gui->CursorY(), gui->CursorX())) {
210 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "background", md.mat->GetName());
211 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "matcolor", "1 1 1 1");
212 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "text", "");
218 if (currentMarker == -1) {
219 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "matcolor", "0 0 0 0");
220 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "text", "No Preview");
222 markerData_t &md = markerTimes[currentMarker];
223 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "background", md.mat->GetName());
224 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "matcolor", "1 1 1 1");
225 gui->GetDesktop()->SetChildWinVarVal("markerBackground", "text", "");
231 void idMarkerWindow::Point(int x, int y, dword *out, dword color) {
232 int index = (63-y) * 512 + x;
233 if (index >= 0 && index < 512 * 64) {
236 common->Warning("Out of bounds on point %i : %i", x, y);
240 void idMarkerWindow::Line(int x1, int y1, int x2, int y2, dword* out, dword color) {
241 int deltax = abs(x2 - x1);
242 int deltay = abs(y2 - y1);
243 int incx = (x1 > x2) ? -1 : 1;
244 int incy = (y1 > y2) ? -1 : 1;
246 if (deltax > deltay) {
248 up = right - deltax * 2;
249 dir = right - deltax;
250 while (deltax-- >= 0) {
251 Point(x1, y1, out, color);
253 y1 += (dir > 0) ? incy : 0;
254 dir += (dir > 0) ? up : right;
258 up = right - deltay * 2;
259 dir = right - deltay;
260 while ( deltay-- >= 0) {
261 Point(x1, y1, out, color);
262 x1 += (dir > 0) ? incx : 0;
264 dir += (dir > 0) ? up : right;
270 void idMarkerWindow::Activate(bool activate, idStr &act) {
271 idWindow::Activate(activate, act);
274 gui->GetDesktop()->SetChildWinVarVal("markerText", "text", "");
275 imageBuff = (dword*)Mem_Alloc(512*64*4);
280 statData = gui->State().GetString( "statData" );
282 if (statData.Length()) {
283 idFile *file = fileSystem->OpenFileRead(statData);
285 file->Read(&numStats, sizeof(numStats));
286 file->Read(loggedStats, numStats * sizeof(loggedStats[0]));
287 for (i = 0; i < numStats; i++) {
288 if (loggedStats[i].health < 0) {
289 loggedStats[i].health = 0;
291 if (loggedStats[i].stamina < 0) {
292 loggedStats[i].stamina = 0;
294 if (loggedStats[i].heartRate < 0) {
295 loggedStats[i].heartRate = 0;
297 if (loggedStats[i].combat < 0) {
298 loggedStats[i].combat = 0;
301 fileSystem->CloseFile(file);
305 if (numStats > 1 && background) {
306 idStr markerPath = statData;
307 markerPath.StripFilename();
309 markers = fileSystem->ListFiles( markerPath, ".tga", false, true );
311 for ( i = 0; i < markers->GetNumFiles(); i++ ) {
312 name = markers->GetFile( i );
314 md.mat = declManager->FindMaterial( name );
315 md.mat->SetSort( SS_GUI );
317 name.StripFileExtension();
318 md.time = atoi(name);
319 markerTimes.Append(md);
321 fileSystem->FreeFileList( markers );
322 memset(imageBuff, 0, 512*64*4);
323 float step = 511.0f / (numStats - 1);
325 float x1, y1, x2, y2;
327 for (i = 0; i < numStats-1; i++) {
330 y1 = 63 * ((float)loggedStats[i].health / HEALTH_MAX);
331 y2 = 63 * ((float)loggedStats[i+1].health / HEALTH_MAX);
332 Line(x1, y1, x2, y2, imageBuff, 0xff0000ff);
333 y1 = 63 * ((float)loggedStats[i].heartRate / RATE_MAX);
334 y2 = 63 * ((float)loggedStats[i+1].heartRate / RATE_MAX);
335 Line(x1, y1, x2, y2, imageBuff, 0xff00ff00);
336 // stamina not quite as high on graph so health does not get obscured with both at 100%
337 y1 = 62 * ((float)loggedStats[i].stamina / STAMINA_MAX);
338 y2 = 62 * ((float)loggedStats[i+1].stamina / STAMINA_MAX);
339 Line(x1, y1, x2, y2, imageBuff, 0xffff0000);
340 y1 = 63 * ((float)loggedStats[i].combat / COMBAT_MAX);
341 y2 = 63 * ((float)loggedStats[i+1].combat / COMBAT_MAX);
342 Line(x1, y1, x2, y2, imageBuff, 0xff00ffff);
344 const shaderStage_t *stage = background->GetStage(0);
346 stage->texture.image->UploadScratch((byte*)imageBuff, 512, 64);
353 void idMarkerWindow::MouseExit() {
354 idWindow::MouseExit();
357 void idMarkerWindow::MouseEnter() {
358 idWindow::MouseEnter();