UFO: Alien Invasion
Loading...
Searching...
No Matches
ui_node_geoscape.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "../../DateTime.h"
26#include "../ui_nodes.h"
27#include "../ui_input.h"
28#include "../ui_parse.h"
29#include "../ui_behaviour.h"
30#include "../ui_actions.h"
31#include "../ui_render.h"
32#include "ui_node_geoscape.h"
35#include "../../cl_shared.h"
36#include "../../cgame/cl_game.h"
38#include "../../input/cl_keys.h"
39
41
42#define EXTRADATA_TYPE mapExtraData_t
43#define EXTRADATA(node) UI_EXTRADATA(node, EXTRADATA_TYPE)
44#define EXTRADATACONST(node) UI_EXTRADATACONST(node, EXTRADATA_TYPE)
45
55
60static int oldMousePosX = 0;
61
66static int oldMousePosY = 0;
67
73static const float ROTATE_SPEED = 0.5f;
74static const float GLOBE_ROTATE = -90.0f;
75static const float SMOOTHING_STEP_2D = 0.02f;
76static const float SMOOTHACCELERATION = 0.06f;
77
82
83// FIXME: don't make this static
85
88
91
92#define DAWN 0.03
93
99{
100 vec3_t diff;
101 const float diffZoom = UI_MAPEXTRADATACONST(node).smoothFinalZoom - UI_MAPEXTRADATACONST(node).zoom;
102
103 VectorSubtract(UI_MAPEXTRADATACONST(node).smoothFinalGlobeAngle, UI_MAPEXTRADATACONST(node).angles, diff);
104
105 if (UI_MAPEXTRADATACONST(node).smoothDeltaLength > UI_MAPEXTRADATACONST(node).smoothDeltaZoom) {
106 /* when we rotate (and zoom) */
107 const float diffAngle = VectorLength(diff);
108 const float epsilon = 0.1f;
109 if (diffAngle > epsilon) {
110 float rotationSpeed;
111 /* Append the old speed to the new speed if this is the first half of a new rotation, but never exceed the max speed.
112 * This allows the globe to rotate at maximum speed when the button is held down. */
113 rotationSpeed = sin(3.05f * diffAngle / UI_MAPEXTRADATACONST(node).smoothDeltaLength) * diffAngle;
114 if (diffAngle / UI_MAPEXTRADATACONST(node).smoothDeltaLength > 0.5)
115 rotationSpeed = std::min(diffAngle, UI_MAPEXTRADATACONST(node).curRotationSpeed + rotationSpeed * 0.5f);
116
117 UI_MAPEXTRADATA(node).curRotationSpeed = rotationSpeed;
118 VectorScale(diff, SMOOTHACCELERATION / diffAngle * rotationSpeed, diff);
119 VectorAdd(UI_MAPEXTRADATACONST(node).angles, diff, UI_MAPEXTRADATA(node).angles);
120 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).zoom + SMOOTHACCELERATION * diffZoom / diffAngle * rotationSpeed;
121 return;
122 }
123 } else {
124 const float epsilonZoom = 0.01f;
125 /* when we zoom only */
126 if (fabsf(diffZoom) > epsilonZoom) {
127 float speed;
128 /* Append the old speed to the new speed if this is the first half of a new zoom operation, but never exceed the max speed.
129 * This allows the globe to zoom at maximum speed when the button is held down. */
130 if (fabsf(diffZoom) / UI_MAPEXTRADATACONST(node).smoothDeltaZoom > 0.5f) {
131 const float maxSpeed = SMOOTHACCELERATION * 2.0f;
132 const float newSpeed = UI_MAPEXTRADATACONST(node).curZoomSpeed + sin(3.05 * (fabs(diffZoom) / UI_MAPEXTRADATACONST(node).smoothDeltaZoom)) * SMOOTHACCELERATION;
133 speed = std::min(maxSpeed, newSpeed);
134 } else {
135 speed = sin(3.05 * (fabs(diffZoom) / UI_MAPEXTRADATACONST(node).smoothDeltaZoom)) * SMOOTHACCELERATION * 2.0;
136 }
137 UI_MAPEXTRADATA(node).curZoomSpeed = speed;
138 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).zoom + diffZoom * speed;
139 return;
140 }
141 }
142
143 /* if we reach this point, that means that movement is over */
144 VectorCopy(UI_MAPEXTRADATACONST(node).smoothFinalGlobeAngle, UI_MAPEXTRADATA(node).angles);
145 UI_MAPEXTRADATA(node).smoothRotation = false;
146 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).smoothFinalZoom;
147}
148
155{
156 const float dist1 = UI_MAPEXTRADATACONST(node).smoothFinal2DGeoscapeCenter[0] - UI_MAPEXTRADATACONST(node).center[0];
157 const float dist2 = UI_MAPEXTRADATACONST(node).smoothFinal2DGeoscapeCenter[1] - UI_MAPEXTRADATACONST(node).center[1];
158 const float length = sqrt(dist1 * dist1 + dist2 * dist2);
159
161 UI_MAPEXTRADATA(node).center[0] = UI_MAPEXTRADATACONST(node).smoothFinal2DGeoscapeCenter[0];
162 UI_MAPEXTRADATA(node).center[1] = UI_MAPEXTRADATACONST(node).smoothFinal2DGeoscapeCenter[1];
163 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).smoothFinalZoom;
164 UI_MAPEXTRADATA(node).smoothRotation = false;
165 } else {
166 const float diffZoom = UI_MAPEXTRADATACONST(node).smoothFinalZoom - UI_MAPEXTRADATACONST(node).zoom;
167 UI_MAPEXTRADATA(node).center[0] = UI_MAPEXTRADATACONST(node).center[0] + SMOOTHING_STEP_2D * dist1 / length;
168 UI_MAPEXTRADATA(node).center[1] = UI_MAPEXTRADATACONST(node).center[1] + SMOOTHING_STEP_2D * dist2 / length;
169 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).zoom + SMOOTHING_STEP_2D * diffZoom;
170 }
171}
172
179{
180 const float dphi = (float) 2 * M_PI / DAN_WIDTH;
181 const float da = M_PI / 2 * (HIGH_LAT - LOW_LAT) / DAN_HEIGHT;
182 const float sin_q = sin(q);
183 const float cos_q = cos(q);
184 float sin_phi[DAN_WIDTH], cos_phi[DAN_WIDTH];
185 byte* px;
186
187 for (int x = 0; x < DAN_WIDTH; x++) {
188 const float phi = x * dphi - q;
189 sin_phi[x] = sin(phi);
190 cos_phi[x] = cos(phi);
191 }
192
193 /* calculate */
194 px = UI_MAPEXTRADATA(node).r_dayandnightAlpha;
195 for (int y = 0; y < DAN_HEIGHT; y++) {
196 const float a = sin(M_PI / 2 * HIGH_LAT - y * da);
197 const float root = sqrt(1 - a * a);
198 for (int x = 0; x < DAN_WIDTH; x++) {
199 const float pos = sin_phi[x] * root * sin_q - (a * SIN_ALPHA + cos_phi[x] * root * COS_ALPHA) * cos_q;
200
201 if (pos >= DAWN)
202 *px++ = 255;
203 else if (pos <= -DAWN)
204 *px++ = 0;
205 else
206 *px++ = (byte) (128.0 * (pos / DAWN + 1));
207 }
208 }
209
210 /* upload alpha map into the r_dayandnighttexture */
211 R_UploadAlpha(r_dayandnightTexture, UI_MAPEXTRADATA(node).r_dayandnightAlpha);
212}
213
215{
216 vec2_t screenPos;
217
218 geoscapeNode = node;
219 UI_MAPEXTRADATA(node).flatgeoscape = cl_3dmap->integer == 0;
220 UI_MAPEXTRADATA(node).radarOverlay = Cvar_GetValue("geo_overlay_radar");
221 UI_MAPEXTRADATA(node).nationOverlay = Cvar_GetValue("geo_overlay_nation");
222 UI_MAPEXTRADATA(node).xviOverlay = Cvar_GetValue("geo_overlay_xvi");
223 UI_MAPEXTRADATA(node).ambientLightFactor = cl_3dmapAmbient->value;
224 UI_MAPEXTRADATA(node).mapzoommin = cl_mapzoommin->value;
225 UI_MAPEXTRADATA(node).mapzoommax = cl_mapzoommax->value;
226
227 UI_GetNodeAbsPos(node, UI_MAPEXTRADATA(node).mapPos);
228 Vector2Copy(node->box.size, UI_MAPEXTRADATA(node).mapSize);
229 if (!UI_MAPEXTRADATACONST(node).flatgeoscape) {
230 /* remove the left padding */
231 UI_MAPEXTRADATA(node).mapSize[0] -= UI_MAPEXTRADATACONST(node).paddingRight;
232 }
233
234 /* Draw geoscape */
235 UI_GetNodeScreenPos(node, screenPos);
236 UI_PushClipRect(screenPos[0], screenPos[1], node->box.size[0], node->box.size[1]);
237
238 if (UI_MAPEXTRADATACONST(node).smoothRotation) {
239 if (UI_MAPEXTRADATACONST(node).flatgeoscape)
240 smoothTranslate(node);
241 else
242 smoothRotate(node);
243 }
244
245 geoscapeData_t& data = *UI_MAPEXTRADATA(node).geoscapeData;
246 data.geoscapeNode = node;
248 if (!data.active)
249 return;
250
251 const char* map = data.map;
252
253 /* Draw the map and markers */
254 if (UI_MAPEXTRADATACONST(node).flatgeoscape) {
255 /* the last q value for the 2d geoscape night overlay */
256 static float lastQ = 0.0f;
257
258 /* the sun is not always in the plane of the equator on earth - calculate the angle the sun is at */
259 const float q = (data.date.getDateAsDays() % DateTime::DAYS_PER_YEAR + (float)(data.date.getTimeAsSeconds() / (DateTime::SECONDS_PER_HOUR * 6)) / 4) * 2 * M_PI / DateTime::DAYS_PER_YEAR - M_PI;
260 if (lastQ != q) {
262 lastQ = q;
263 }
264 R_DrawFlatGeoscape(UI_MAPEXTRADATACONST(node).mapPos, UI_MAPEXTRADATACONST(node).mapSize, (float) data.date.getTimeAsSeconds() / DateTime::SECONDS_PER_DAY,
265 UI_MAPEXTRADATACONST(node).center[0], UI_MAPEXTRADATACONST(node).center[1], 0.5 / UI_MAPEXTRADATACONST(node).zoom, map,
266 data.nationOverlay, data.xviOverlay, data.radarOverlay, r_dayandnightTexture, r_xviTexture, r_radarTexture);
267
269 } else {
270 bool disableSolarRender = false;
271 if (UI_MAPEXTRADATACONST(node).zoom > 3.3)
272 disableSolarRender = true;
273
275
276 R_Draw3DGlobe(UI_MAPEXTRADATACONST(node).mapPos, UI_MAPEXTRADATACONST(node).mapSize, data.date.getDateAsDays(), data.date.getTimeAsSeconds(),
277 UI_MAPEXTRADATACONST(node).angles, UI_MAPEXTRADATACONST(node).zoom, map, disableSolarRender,
278 UI_MAPEXTRADATACONST(node).ambientLightFactor, UI_MAPEXTRADATA(node).nationOverlay,
279 UI_MAPEXTRADATA(node).xviOverlay, UI_MAPEXTRADATA(node).radarOverlay, r_xviTexture, r_radarTexture,
280 true);
281
283
284 R_DrawBloom();
286 }
287
289}
290
292{
293 switch (mode) {
294 case MODE_SHIFT2DMAP:
295 {
296 const float zoom = 0.5 / UI_MAPEXTRADATACONST(node).zoom;
297 /* shift the map */
298 UI_MAPEXTRADATA(node).center[0] -= (float) (mousePosX - oldMousePosX) / (node->box.size[0] * UI_MAPEXTRADATACONST(node).zoom);
299 UI_MAPEXTRADATA(node).center[1] -= (float) (mousePosY - oldMousePosY) / (node->box.size[1] * UI_MAPEXTRADATACONST(node).zoom);
300 for (int i = 0; i < 2; i++) {
301 /* clamp to min/max values */
302 while (UI_MAPEXTRADATACONST(node).center[i] < 0.0)
303 UI_MAPEXTRADATA(node).center[i] += 1.0;
304 while (UI_MAPEXTRADATACONST(node).center[i] > 1.0)
305 UI_MAPEXTRADATA(node).center[i] -= 1.0;
306 }
307 if (UI_MAPEXTRADATACONST(node).center[1] < zoom)
308 UI_MAPEXTRADATA(node).center[1] = zoom;
309 if (UI_MAPEXTRADATACONST(node).center[1] > 1.0 - zoom)
310 UI_MAPEXTRADATA(node).center[1] = 1.0 - zoom;
311 break;
312 }
313
314 case MODE_SHIFT3DMAP:
315 /* rotate a model */
318
319 /* clamp the UI_MAPEXTRADATACONST(node).angles */
320 while (UI_MAPEXTRADATACONST(node).angles[YAW] > 0.0)
321 UI_MAPEXTRADATA(node).angles[YAW] = 0.0;
322 while (UI_MAPEXTRADATACONST(node).angles[YAW] < -180.0)
323 UI_MAPEXTRADATA(node).angles[YAW] = -180.0;
324
325 while (UI_MAPEXTRADATACONST(node).angles[PITCH] > 180.0)
326 UI_MAPEXTRADATA(node).angles[PITCH] -= 360.0;
327 while (UI_MAPEXTRADATACONST(node).angles[PITCH] < -180.0)
328 UI_MAPEXTRADATA(node).angles[PITCH] += 360.0;
329 break;
330 case MODE_ZOOMMAP:
331 {
332 const float zoom = 0.5 / UI_MAPEXTRADATACONST(node).zoom;
333 /* zoom the map */
334 UI_MAPEXTRADATA(node).zoom *= pow(0.995, mousePosY - oldMousePosY);
335 if (UI_MAPEXTRADATACONST(node).zoom < UI_MAPEXTRADATACONST(node).mapzoommin)
336 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).mapzoommin;
337 else if (UI_MAPEXTRADATACONST(node).zoom > UI_MAPEXTRADATACONST(node).mapzoommax)
338 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).mapzoommax;
339
340 if (UI_MAPEXTRADATACONST(node).center[1] < zoom)
341 UI_MAPEXTRADATA(node).center[1] = zoom;
342 if (UI_MAPEXTRADATACONST(node).center[1] > 1.0 - zoom)
343 UI_MAPEXTRADATA(node).center[1] = 1.0 - zoom;
344 break;
345 }
346 default:
347 assert(false);
348 break;
349 }
350 oldMousePosX = x;
351 oldMousePosY = y;
352}
353
355{
356 UI_SetMouseCapture(node);
357 if (UI_MAPEXTRADATACONST(node).flatgeoscape)
359 else
361 UI_MAPEXTRADATA(node).smoothRotation = false;
362 oldMousePosX = x;
363 oldMousePosY = y;
364}
365
372void uiGeoscapeNode::screenToMap (const uiNode_t* node, int x, int y, vec2_t pos)
373{
374 pos[0] = (((UI_MAPEXTRADATACONST(node).mapPos[0] - x) / UI_MAPEXTRADATACONST(node).mapSize[0] + 0.5) / UI_MAPEXTRADATACONST(node).zoom
375 - (UI_MAPEXTRADATACONST(node).center[0] - 0.5)) * 360.0;
376 pos[1] = (((UI_MAPEXTRADATACONST(node).mapPos[1] - y) / UI_MAPEXTRADATACONST(node).mapSize[1] + 0.5) / UI_MAPEXTRADATACONST(node).zoom
377 - (UI_MAPEXTRADATACONST(node).center[1] - 0.5)) * 180.0;
378
379 while (pos[0] > 180.0)
380 pos[0] -= 360.0;
381 while (pos[0] < -180.0)
382 pos[0] += 360.0;
383}
384
392void uiGeoscapeNode::screenTo3DMap (const uiNode_t* node, int x, int y, vec2_t pos)
393{
394 vec2_t mid;
395 vec3_t v, v1, rotationAxis;
396 float dist;
397 const float radius = GLOBE_RADIUS;
398
399 /* set mid to the coordinates of the center of the globe */
400 Vector2Set(mid, UI_MAPEXTRADATACONST(node).mapPos[0] + UI_MAPEXTRADATACONST(node).mapSize[0] / 2.0f,
401 UI_MAPEXTRADATACONST(node).mapPos[1] + UI_MAPEXTRADATACONST(node).mapSize[1] / 2.0f);
402
403 /* stop if we click outside the globe (distance is the distance of the point to the center of the globe) */
404 dist = sqrt((x - mid[0]) * (x - mid[0]) + (y - mid[1]) * (y - mid[1]));
405 if (dist > radius) {
406 Vector2Set(pos, -1.0, -1.0);
407 return;
408 }
409
410 /* calculate the coordinates in the local frame
411 * this frame is the frame of the screen.
412 * v[0] is the vertical axis of the screen
413 * v[1] is the horizontal axis of the screen
414 * v[2] is the axis perpendicular to the screen - we get its value knowing that norm of v is egal to radius
415 * (because the point is on the globe) */
416 v[0] = - (y - mid[1]);
417 v[1] = - (x - mid[0]);
418 v[2] = - sqrt(radius * radius - (x - mid[0]) * (x - mid[0]) - (y - mid[1]) * (y - mid[1]));
420
421 /* rotate the vector to switch of reference frame
422 * note the ccs.angles[ROLL] is always 0, so there is only 2 rotations and not 3
423 * and that GLOBE_ROTATE is already included in ccs.angles[YAW]
424 * first rotation is along the horizontal axis of the screen, to put north-south axis of the earth
425 * perpendicular to the screen */
426 VectorSet(rotationAxis, 0, 1, 0);
427 RotatePointAroundVector(v1, rotationAxis, v, UI_MAPEXTRADATACONST(node).angles[YAW]);
428
429 /* second rotation is to rotate the earth around its north-south axis
430 * so that Greenwich meridian is along the vertical axis of the screen */
431 VectorSet(rotationAxis, 0, 0, 1);
432 RotatePointAroundVector(v, rotationAxis, v1, UI_MAPEXTRADATACONST(node).angles[PITCH]);
433
434 /* we therefore got in v the coordinates of the point in the static frame of the earth
435 * that we can convert in polar coordinates to get its latitude and longitude */
436 VecToPolar(v, pos);
437}
438
439void uiGeoscapeNode::onLeftClick (uiNode_t* node, int x, int y)
440{
441 if (mode != MODE_NULL)
442 return;
443
444 vec2_t pos;
445
446 /* get map position */
447 if (!UI_MAPEXTRADATACONST(node).flatgeoscape)
448 screenTo3DMap(node, x, y, pos);
449 else
450 screenToMap(node, x, y, pos);
451
452 GAME_MapClick(node, x, y, pos);
453}
454
455bool uiGeoscapeNode::onStartDragging (uiNode_t* node, int startX, int startY, int x, int y, int button)
456{
457 switch (button) {
458 case K_MOUSE1:
459 case K_MOUSE3:
461 return true;
462 case K_MOUSE2:
463 UI_SetMouseCapture(node);
467 return true;
468 }
469 return false;
470}
471
472void uiGeoscapeNode::onMouseUp (uiNode_t* node, int x, int y, int button)
473{
474 if (mode != MODE_NULL) {
476 mode = MODE_NULL;
477 }
478}
479
488
493void uiGeoscapeNode::zoom (uiNode_t* node, bool out)
494{
495 UI_MAPEXTRADATA(node).zoom *= pow(0.995, (out ? 10: -10));
496 if (UI_MAPEXTRADATACONST(node).zoom < UI_MAPEXTRADATACONST(node).mapzoommin)
497 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).mapzoommin;
498 else if (UI_MAPEXTRADATACONST(node).zoom > UI_MAPEXTRADATACONST(node).mapzoommax)
499 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).mapzoommax;
500
501 if (UI_MAPEXTRADATACONST(node).flatgeoscape) {
502 if (UI_MAPEXTRADATACONST(node).center[1] < 0.5 / UI_MAPEXTRADATACONST(node).zoom)
503 UI_MAPEXTRADATA(node).center[1] = 0.5 / UI_MAPEXTRADATACONST(node).zoom;
504 if (UI_MAPEXTRADATACONST(node).center[1] > 1.0 - 0.5 / UI_MAPEXTRADATACONST(node).zoom)
505 UI_MAPEXTRADATA(node).center[1] = 1.0 - 0.5 / UI_MAPEXTRADATACONST(node).zoom;
506 }
507 UI_MAPEXTRADATA(node).smoothRotation = false;
508}
509
510bool uiGeoscapeNode::onScroll (uiNode_t* node, int deltaX, int deltaY)
511{
512 bool down = deltaY > 0;
513 if (deltaY == 0)
514 return false;
515 zoom(node, down);
516 return true;
517}
518
523{
524 Vector4Set(node->color, 1, 1, 1, 1);
525
526 OBJZERO(EXTRADATA(node));
527 EXTRADATA(node).angles[YAW] = GLOBE_ROTATE;
528 EXTRADATA(node).center[0] = EXTRADATA(node).center[1] = 0.5;
529 EXTRADATA(node).zoom = 1.0;
530 Vector2Set(EXTRADATA(node).smoothFinal2DGeoscapeCenter, 0.5, 0.5);
531 VectorSet(EXTRADATA(node).smoothFinalGlobeAngle, 0, GLOBE_ROTATE, 0);
532
533 /* @todo: allocate this on a per node basis - and remove the global variable geoscapeData */
534 EXTRADATA(node).geoscapeData = &geoscapeData;
535 /* EXTRADATA(node).geoscapeData = Mem_AllocType(geoscapeData_t); */
536
538 EXTRADATA(node).r_dayandnightAlpha = Mem_AllocTypeN(byte, DAN_WIDTH * DAN_HEIGHT);
539
540 r_dayandnightTexture = R_LoadImageData("***r_dayandnighttexture***", nullptr, DAN_WIDTH, DAN_HEIGHT, it_effect);
541 r_radarTexture = R_LoadImageData("***r_radarTexture***", nullptr, RADAR_WIDTH, RADAR_HEIGHT, it_effect);
542 r_xviTexture = R_LoadImageData("***r_xvitexture***", nullptr, XVI_WIDTH, XVI_HEIGHT, it_effect);
543}
544
545static void UI_GeoscapeNodeZoomIn (uiNode_t* node, const uiCallContext_t* context)
546{
547 uiGeoscapeNode* m = static_cast<uiGeoscapeNode*>(node->behaviour->manager.get());
548 m->zoom(node, false);
549}
550
551static void UI_GeoscapeNodeZoomOut (uiNode_t* node, const uiCallContext_t* context)
552{
553 uiGeoscapeNode* m = static_cast<uiGeoscapeNode*>(node->behaviour->manager.get());
554 m->zoom(node, true);
555}
556
561static void UI_GeoscapeNodeZoom_f (void)
562{
563 const char* cmd;
564 const float zoomAmount = 50.0f;
565
566 if (Cmd_Argc() != 2) {
567 Com_Printf("Usage: %s <in|out>\n", Cmd_Argv(0));
568 return;
569 }
570
571 cmd = Cmd_Argv(1);
572 uiNode_t* node = geoscapeNode;
573 if (!node)
574 return;
575
576 switch (cmd[0]) {
577 case 'i':
578 UI_MAPEXTRADATA(node).smoothFinalZoom = UI_MAPEXTRADATACONST(node).zoom * powf(0.995, -zoomAmount);
579 break;
580 case 'o':
581 UI_MAPEXTRADATA(node).smoothFinalZoom = UI_MAPEXTRADATACONST(node).zoom * powf(0.995, zoomAmount);
582 break;
583 default:
584 Com_Printf("UI_GeoscapeNodeZoom_f: Invalid parameter: %s\n", cmd);
585 return;
586 }
587
588 if (UI_MAPEXTRADATACONST(node).smoothFinalZoom < UI_MAPEXTRADATACONST(node).mapzoommin)
589 UI_MAPEXTRADATA(node).smoothFinalZoom = UI_MAPEXTRADATACONST(node).mapzoommin;
590 else if (UI_MAPEXTRADATACONST(node).smoothFinalZoom > UI_MAPEXTRADATACONST(node).mapzoommax)
591 UI_MAPEXTRADATA(node).smoothFinalZoom = UI_MAPEXTRADATACONST(node).mapzoommax;
592
593 if (UI_MAPEXTRADATACONST(node).flatgeoscape) {
594 UI_MAPEXTRADATA(node).zoom = UI_MAPEXTRADATACONST(node).smoothFinalZoom;
595 if (UI_MAPEXTRADATACONST(node).center[1] < 0.5 / UI_MAPEXTRADATACONST(node).zoom)
596 UI_MAPEXTRADATA(node).center[1] = 0.5 / UI_MAPEXTRADATACONST(node).zoom;
597 if (UI_MAPEXTRADATACONST(node).center[1] > 1.0 - 0.5 / UI_MAPEXTRADATACONST(node).zoom)
598 UI_MAPEXTRADATA(node).center[1] = 1.0 - 0.5 / UI_MAPEXTRADATACONST(node).zoom;
599 } else {
600 VectorCopy(UI_MAPEXTRADATACONST(node).angles, UI_MAPEXTRADATA(node).smoothFinalGlobeAngle);
601 UI_MAPEXTRADATA(node).smoothDeltaLength = 0;
602 UI_MAPEXTRADATA(node).smoothRotation = true;
603 UI_MAPEXTRADATA(node).smoothDeltaZoom = fabs(UI_MAPEXTRADATACONST(node).smoothFinalZoom - UI_MAPEXTRADATACONST(node).zoom);
604 }
605}
606
611static void UI_GeoscapeNodeScroll_f (void)
612{
613 const char* cmd;
614 float scrollX = 0.0f, scrollY = 0.0f;
615 const float scrollAmount = 80.0f;
616
617 if (Cmd_Argc() != 2) {
618 Com_Printf("Usage: %s <up|down|left|right>\n", Cmd_Argv(0));
619 return;
620 }
621
622 cmd = Cmd_Argv(1);
623
624 uiNode_t* node = geoscapeNode;
625 if (!node)
626 return;
627
628 switch (cmd[0]) {
629 case 'l':
630 scrollX = scrollAmount;
631 break;
632 case 'r':
633 scrollX = -scrollAmount;
634 break;
635 case 'u':
636 scrollY = scrollAmount;
637 break;
638 case 'd':
639 scrollY = -scrollAmount;
640 break;
641 default:
642 Com_Printf("UI_GeoscapeNodeScroll_f: Invalid parameter\n");
643 return;
644 }
645
646 if (!UI_MAPEXTRADATACONST(node).flatgeoscape) {
647 /* case 3D geoscape */
648 vec3_t diff;
649
650 VectorCopy(UI_MAPEXTRADATACONST(node).angles, UI_MAPEXTRADATA(node).smoothFinalGlobeAngle);
651
652 /* rotate a model */
653 UI_MAPEXTRADATA(node).smoothFinalGlobeAngle[PITCH] += ROTATE_SPEED * (scrollX) / UI_MAPEXTRADATACONST(node).zoom;
654 UI_MAPEXTRADATA(node).smoothFinalGlobeAngle[YAW] -= ROTATE_SPEED * (scrollY) / UI_MAPEXTRADATACONST(node).zoom;
655
656 while (UI_MAPEXTRADATACONST(node).smoothFinalGlobeAngle[YAW] < -180.0) {
657 UI_MAPEXTRADATA(node).smoothFinalGlobeAngle[YAW] = -180.0;
658 }
659 while (UI_MAPEXTRADATACONST(node).smoothFinalGlobeAngle[YAW] > 0.0) {
660 UI_MAPEXTRADATA(node).smoothFinalGlobeAngle[YAW] = 0.0;
661 }
662
663 while (UI_MAPEXTRADATACONST(node).smoothFinalGlobeAngle[PITCH] > 180.0) {
664 UI_MAPEXTRADATA(node).smoothFinalGlobeAngle[PITCH] -= 360.0;
665 UI_MAPEXTRADATA(node).angles[PITCH] -= 360.0;
666 }
667 while (UI_MAPEXTRADATACONST(node).smoothFinalGlobeAngle[PITCH] < -180.0) {
668 UI_MAPEXTRADATA(node).smoothFinalGlobeAngle[PITCH] += 360.0;
669 UI_MAPEXTRADATA(node).angles[PITCH] += 360.0;
670 }
671 VectorSubtract(UI_MAPEXTRADATACONST(node).smoothFinalGlobeAngle, UI_MAPEXTRADATACONST(node).angles, diff);
672 UI_MAPEXTRADATA(node).smoothDeltaLength = VectorLength(diff);
673
674 UI_MAPEXTRADATA(node).smoothFinalZoom = UI_MAPEXTRADATACONST(node).zoom;
675 UI_MAPEXTRADATA(node).smoothDeltaZoom = 0.0f;
676 UI_MAPEXTRADATA(node).smoothRotation = true;
677 } else {
678 /* shift the map */
679 UI_MAPEXTRADATA(node).center[0] -= (float) (scrollX) / (UI_MAPEXTRADATACONST(node).mapSize[0] * UI_MAPEXTRADATACONST(node).zoom);
680 UI_MAPEXTRADATA(node).center[1] -= (float) (scrollY) / (UI_MAPEXTRADATACONST(node).mapSize[1] * UI_MAPEXTRADATACONST(node).zoom);
681 for (int i = 0; i < 2; i++) {
682 while (UI_MAPEXTRADATACONST(node).center[i] < 0.0)
683 UI_MAPEXTRADATA(node).center[i] += 1.0;
684 while (UI_MAPEXTRADATACONST(node).center[i] > 1.0)
685 UI_MAPEXTRADATA(node).center[i] -= 1.0;
686 }
687 if (UI_MAPEXTRADATACONST(node).center[1] < 0.5 / UI_MAPEXTRADATACONST(node).zoom)
688 UI_MAPEXTRADATA(node).center[1] = 0.5 / UI_MAPEXTRADATACONST(node).zoom;
689 if (UI_MAPEXTRADATACONST(node).center[1] > 1.0 - 0.5 / UI_MAPEXTRADATACONST(node).zoom)
690 UI_MAPEXTRADATA(node).center[1] = 1.0 - 0.5 / UI_MAPEXTRADATACONST(node).zoom;
691 }
692}
693
695{
696 behaviour->name = "geoscape";
697 behaviour->manager = UINodePtr(new uiGeoscapeNode());
698 behaviour->extraDataSize = sizeof(EXTRADATA_TYPE);
699 behaviour->lua_SWIG_typeinfo = UI_SWIG_TypeQuery("uiGeoscapeNode_t *");
700
701 /* Use a right padding. */
702 UI_RegisterExtradataNodeProperty(behaviour, "padding-right", V_FLOAT, EXTRADATA_TYPE, paddingRight);
703 /* Call it to zoom out of the map */
704 UI_RegisterNodeMethod(behaviour, "zoomin", UI_GeoscapeNodeZoomIn);
705 /* Call it to zoom into the map */
706 UI_RegisterNodeMethod(behaviour, "zoomout", UI_GeoscapeNodeZoomOut);
707
710
711 cl_3dmap = Cvar_Get("cl_3dmap", "1", CVAR_ARCHIVE, "3D geoscape or flat geoscape");
712 cl_3dmapAmbient = Cvar_Get("cl_3dmapAmbient", "0", CVAR_ARCHIVE, "3D geoscape ambient lighting factor");
713 cl_mapzoommax = Cvar_Get("cl_mapzoommax", "6.0", CVAR_ARCHIVE, "Maximum geoscape zooming value");
714 cl_mapzoommin = Cvar_Get("cl_mapzoommin", "1.0", CVAR_ARCHIVE, "Minimum geoscape zooming value");
715}
DateTime class definition.
void GAME_DrawMap(geoscapeData_t *data)
Definition cl_game.cpp:931
void GAME_DrawMapMarkers(uiNode_t *node)
Definition cl_game.cpp:938
geoscapeData_t geoscapeData
Definition cl_game.cpp:147
void GAME_MapClick(uiNode_t *node, int x, int y, const vec2_t pos)
Definition cl_game.cpp:945
Shared game type headers.
int mousePosY
Definition cl_input.cpp:76
static int oldMousePosX
Definition cl_input.cpp:77
int down
Definition cl_input.cpp:66
int mousePosX
Definition cl_input.cpp:76
static int oldMousePosY
Definition cl_input.cpp:77
External (non-keyboard) input devices.
Header file for keyboard handler.
@ K_MOUSE2
Definition cl_keys.h:47
@ K_MOUSE1
Definition cl_keys.h:46
@ K_MOUSE3
Definition cl_keys.h:48
Share stuff between the different cgame implementations.
#define XVI_HEIGHT
Definition cl_shared.h:51
#define XVI_WIDTH
Definition cl_shared.h:50
#define RADAR_WIDTH
Definition cl_shared.h:52
#define RADAR_HEIGHT
Definition cl_shared.h:53
static const int SECONDS_PER_DAY
Definition DateTime.h:43
static const short SECONDS_PER_HOUR
Definition DateTime.h:42
static const int DAYS_PER_YEAR
Definition DateTime.h:37
PointerType get() const
Definition sharedptr.h:197
void onLoading(uiNode_t *node) override
Called before loading. Used to set default attribute values.
void screenToMap(const uiNode_t *node, int x, int y, vec2_t pos)
Return longitude and latitude of a point of the screen for 2D geoscape.
void screenTo3DMap(const uiNode_t *node, int x, int y, vec2_t pos)
Return longitude and latitude of a point of the screen for 3D geoscape (globe).
void smoothTranslate(uiNode_t *node)
smooth translation of the 2D geoscape
void startMouseShifting(uiNode_t *node, int x, int y)
void onMouseUp(uiNode_t *node, int x, int y, int button) override
bool onStartDragging(uiNode_t *node, int startX, int startY, int currentX, int currentY, int button) override
Send mouse event when a pressed mouse button is dragged.
void calcAndUploadDayAndNightTexture(uiNode_t *node, float q)
Applies alpha values to the night overlay image for 2d geoscape.
void onCapturedMouseLost(uiNode_t *node) override
Called when the node have lost the captured node We clean cached data.
void draw(uiNode_t *node) override
void smoothRotate(uiNode_t *node)
smooth rotation of the 3D geoscape
bool onScroll(uiNode_t *node, int deltaX, int deltaY) override
void zoom(uiNode_t *node, bool out)
void onCapturedMouseMove(uiNode_t *node, int x, int y) override
void onLeftClick(uiNode_t *node, int x, int y) override
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition cmd.cpp:516
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition cmd.cpp:505
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition cmd.cpp:744
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
static uiNode_t * geoscapeNode
#define GLOBE_ROTATE
float Cvar_GetValue(const char *varName)
Returns the float value of a cvar.
Definition cvar.cpp:125
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition cvar.cpp:342
#define CVAR_ARCHIVE
Definition cvar.h:40
const char int mode
Definition ioapi.h:41
vec_t VectorNormalize(vec3_t v)
Calculate unit vector for a given vec3_t.
Definition mathlib.cpp:745
vec_t VectorLength(const vec3_t v)
Calculate the length of a vector.
Definition mathlib.cpp:434
void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees)
Rotate a point around a given vector.
Definition mathlib.cpp:849
void VecToPolar(const vec3_t v, vec2_t a)
Converts vector coordinates into polar coordinates.
Definition mathlib.cpp:922
#define HIGH_LAT
Definition mathlib.h:67
#define LOW_LAT
Definition mathlib.h:68
#define YAW
Definition mathlib.h:55
#define PITCH
Definition mathlib.h:54
#define COS_ALPHA
Definition mathlib.h:66
#define SIN_ALPHA
Definition mathlib.h:65
#define M_PI
Definition mathlib.h:34
static struct mdfour * m
Definition md4.cpp:35
#define Mem_AllocTypeN(type, n)
Definition mem.h:38
bool R_EnableRenderbuffer(bool enable)
Enable the render to the framebuffer.
void R_DrawFlatGeoscape(const vec2_t nodePos, const vec2_t nodeSize, float p, float cx, float cy, float iz, const char *map, bool overlayNation, bool overlayXVI, bool overlayRadar, image_t *r_dayandnightTexture, image_t *r_xviTexture, image_t *r_radarTexture)
Draw the day and night images of a flat geoscape multitexture feature is used to blend the images.
void R_DrawBloom(void)
handle post-processing bloom
void R_Draw3DGlobe(const vec2_t pos, const vec2_t size, int day, int second, const vec3_t rotate, float zoom, const char *map, bool disableSolarRender, float ambient, bool overlayNation, bool overlayXVI, bool overlayRadar, image_t *r_xviTexture, image_t *r_radarTexture, bool renderNationGlow)
responsible for drawing the 3d globe on geoscape param[in] rotate the rotate angle of the globe param...
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLsizei const GLvoid * data
Definition r_gl.h:89
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition r_gl.h:110
QGL_EXTERN GLint i
Definition r_gl.h:113
image_t * R_LoadImageData(const char *name, const byte *pic, int width, int height, imagetype_t type)
Creates a new image from RGBA data. Stores it in the gltextures array and also uploads it.
Definition r_image.cpp:475
void R_UploadAlpha(const image_t *image, const byte *alphaData)
Definition r_image.cpp:423
@ it_effect
Definition r_image.h:43
@ V_FLOAT
Definition scripts.h:54
Header for lua script functions.
#define OBJZERO(obj)
Definition shared.h:178
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
node behaviour, how a node work
const char * name
void * lua_SWIG_typeinfo
UINodePtr manager
intptr_t extraDataSize
vec2_t size
Definition ui_nodes.h:52
Contain the context of the calling of a function.
Definition ui_actions.h:208
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
vec4_t color
Definition ui_nodes.h:127
uiBehaviour_t * behaviour
Definition ui_nodes.h:83
uiBox_t box
Definition ui_nodes.h:96
vec_t vec3_t[3]
Definition ufotypes.h:39
uint8_t byte
Definition ufotypes.h:34
vec_t vec2_t[2]
Definition ufotypes.h:38
const struct value_s * UI_RegisterNodeMethod(uiBehaviour_t *behaviour, const char *name, uiNodeMethod_t function)
Register a node method to a behaviour.
#define UI_RegisterExtradataNodeProperty(BEHAVIOUR, NAME, TYPE, EXTRADATATYPE, ATTRIBUTE)
Initialize a property from extradata of node.
void UI_SetMouseCapture(uiNode_t *node)
Captured the mouse into a node.
Definition ui_input.cpp:516
void UI_MouseRelease(void)
Release the captured node.
Definition ui_input.cpp:526
void * UI_SWIG_TypeQuery(const char *name)
This function queries the SWIG type table for a type information structure. It is used in combination...
void UI_GetNodeAbsPos(const uiNode_t *node, vec2_t pos)
Returns the absolute position of a node.
Definition ui_node.cpp:526
void UI_GetNodeScreenPos(const uiNode_t *node, vec2_t pos)
Returns the absolute position of a node in the screen. Screen position is not used for the node rende...
Definition ui_node.cpp:554
SharedPtr< uiNode > UINodePtr
#define EXTRADATA_TYPE
#define EXTRADATA(node)
static int startY
static int startX
static cvar_t * cl_3dmap
image_t * r_dayandnightTexture
static void UI_GeoscapeNodeZoomOut(uiNode_t *node, const uiCallContext_t *context)
#define DAWN
static cvar_t * cl_mapzoommax
static void UI_GeoscapeNodeZoom_f(void)
Command binding for map zooming.
static void UI_GeoscapeNodeScroll_f(void)
Command binding for map scrolling.
mapDragMode_t
Status of the node.
@ MODE_ZOOMMAP
@ MODE_SHIFT3DMAP
@ MODE_NULL
@ MODE_SHIFT2DMAP
void UI_RegisterGeoscapeNode(uiBehaviour_t *behaviour)
static const float SMOOTHING_STEP_2D
image_t * r_xviTexture
static const float SMOOTHACCELERATION
image_t * r_radarTexture
static cvar_t * cl_mapzoommin
static cvar_t * cl_3dmapAmbient
static void UI_GeoscapeNodeZoomIn(uiNode_t *node, const uiCallContext_t *context)
#define DAN_HEIGHT
#define DAN_WIDTH
#define UI_MAPEXTRADATACONST(node)
#define GLOBE_RADIUS
radius of the globe in screen coordinates
#define UI_MAPEXTRADATA(node)
#define ROTATE_SPEED
void UI_PushClipRect(int x, int y, int width, int height)
Definition ui_render.cpp:47
void UI_PopClipRect(void)
Definition ui_render.cpp:52
#define Vector4Set(v, r, g, b, a)
Definition vector.h:62
#define VectorSubtract(a, b, dest)
Definition vector.h:45
#define VectorCopy(src, dest)
Definition vector.h:51
#define Vector2Set(v, x, y)
Definition vector.h:61
#define VectorAdd(a, b, dest)
Definition vector.h:47
#define VectorSet(v, x, y, z)
Definition vector.h:59
#define VectorScale(in, scale, out)
Definition vector.h:79
#define Vector2Copy(src, dest)
Definition vector.h:52