1 /*
2 * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file)
3 *
4 * This file is part of Arx Libertatis.
5 *
6 * Arx Libertatis is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Arx Libertatis is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Arx Libertatis. If not, see <http://www.gnu.org/licenses/>.
18 */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see
33 <http://www.gnu.org/licenses/>.
34
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43
44 #include "core/ArxGame.h"
45
46 #include <stddef.h>
47 #include <cstdio>
48 #include <cstring>
49 #include <algorithm>
50 #include <sstream>
51
52 #include <boost/foreach.hpp>
53
54 #include "ai/PathFinderManager.h"
55 #include "ai/Paths.h"
56
57 #include "animation/Animation.h"
58 #include "animation/Cinematic.h"
59
60 #include "core/Core.h"
61 #include "core/Config.h"
62 #include "core/GameTime.h"
63 #include "core/Localisation.h"
64 #include "core/SaveGame.h"
65 #include "core/Version.h"
66
67 #include "game/Damage.h"
68 #include "game/EntityManager.h"
69 #include "game/Inventory.h"
70 #include "game/Levels.h"
71 #include "game/Missile.h"
72 #include "game/NPC.h"
73 #include "game/Player.h"
74 #include "game/Spells.h"
75
76 #include "graphics/BaseGraphicsTypes.h"
77 #include "graphics/Color.h"
78 #include "graphics/Draw.h"
79 #include "graphics/GraphicsModes.h"
80 #include "graphics/GraphicsTypes.h"
81 #include "graphics/Math.h"
82 #include "graphics/Renderer.h"
83 #include "graphics/Vertex.h"
84 #include "graphics/VertexBuffer.h"
85 #include "graphics/data/Mesh.h"
86 #include "graphics/data/TextureContainer.h"
87 #include "graphics/effects/Fog.h"
88 #include "graphics/font/Font.h"
89 #include "graphics/particle/ParticleEffects.h"
90 #include "graphics/particle/ParticleManager.h"
91 #include "graphics/texture/TextureStage.h"
92
93 #include "gui/Interface.h"
94 #include "gui/Menu.h"
95 #include "gui/MenuWidgets.h"
96 #include "gui/MiniMap.h"
97 #include "gui/Speech.h"
98 #include "gui/Text.h"
99 #include "gui/TextManager.h"
100
101 #include "input/Input.h"
102 #include "input/Keyboard.h"
103
104 #include "math/Angle.h"
105 #include "math/MathFwd.h"
106 #include "math/Rectangle.h"
107 #include "math/Vector2.h"
108 #include "math/Vector3.h"
109
110 #include "io/fs/FilePath.h"
111 #include "io/fs/SystemPaths.h"
112 #include "io/resource/PakReader.h"
113 #include "io/Screenshot.h"
114 #include "io/log/Logger.h"
115
116 #include "platform/Flags.h"
117 #include "platform/Platform.h"
118
119 #include "scene/ChangeLevel.h"
120 #include "scene/Interactive.h"
121 #include "scene/GameSound.h"
122 #include "scene/Light.h"
123 #include "scene/LoadLevel.h"
124 #include "scene/Object.h"
125 #include "scene/Scene.h"
126
127 #include "Configure.h"
128 #include "core/URLConstants.h"
129
130 #ifdef ARX_HAVE_D3D9
131 #include "window/D3D9Window.h"
132 #endif
133 #ifdef ARX_HAVE_SDL
134 #include "window/SDLWindow.h"
135 #endif
136
137 static bool showFPS = false;
138
139 using std::string;
140
141 extern long PLAY_LOADED_CINEMATIC;
142 extern long START_NEW_QUEST;
143 extern long CHANGE_LEVEL_ICON;
144 extern long REFUSE_GAME_RETURN;
145 extern bool PLAYER_MOUSELOOK_ON;
146 extern bool TRUE_PLAYER_MOUSELOOK_ON;
147 extern long FRAME_COUNT;
148 extern long PLAYER_PARALYSED;
149 extern long STOP_KEYBOARD_INPUT;
150 extern long USEINTERNORM;
151 extern long cur_mr;
152 extern long cur_rf;
153 extern long STRIKE_TIME;
154 extern long DeadTime;
155 extern long TRANSPOLYSPOS;
156 extern long FORCE_FRONT_DRAW;
157 extern long LAST_ROOM;
158 extern long LAST_PORTALS_COUNT;
159 extern int iTimeToDrawD7;
160 extern long LaunchDemo;
161
162 extern short uw_mode;
163
164 extern long CURRENT_BASE_FOCAL;
165 extern float BOW_FOCAL;
166
167 extern float GLOBAL_SLOWDOWN;
168 extern float sp_max_start;
169 extern float LAST_FADEVALUE;
170
171 extern float PROGRESS_BAR_TOTAL;
172 extern float PROGRESS_BAR_COUNT;
173 extern float OLD_PROGRESS_BAR_COUNT;
174
175 extern bool bOLD_CLIPP;
176
177 extern void DANAE_KillCinematic();
178 extern void LaunchWaitingCine();
179
180 extern Cinematic* ControlCinematique;
181 extern EERIE_3DOBJ* eyeballobj;
182 extern EERIE_3DOBJ * arrowobj;
183 extern TextureContainer * Movable;
184 extern TextureContainer * tflare;
185 extern Entity * FlyingOverIO;
186 extern E_ARX_STATE_MOUSE eMouseState;
187 extern Vec3f LastValidPlayerPos;
188 extern Color ulBKGColor;
189 extern EERIE_CAMERA conversationcamera;
190 extern ParticleManager * pParticleManager;
191 extern CircularVertexBuffer<TexturedVertex> * pDynamicVertexBuffer_TLVERTEX; // VB using TLVERTEX format.
192 extern CircularVertexBuffer<SMY_VERTEX3> * pDynamicVertexBuffer;
193 extern CMenuState * pMenu;
194
195 extern EERIEMATRIX ProjectionMatrix;
196
197 TextureContainer * ChangeLevel = NULL;
198 TextureContainer * Movable = NULL; // TextureContainer for Movable Items (Red Cross)
199
200 long WILL_QUICKLOAD=0;
201 long WILL_QUICKSAVE=0;
202 long NEED_SPECIAL_RENDEREND=0;
203 long BOOKBUTTON=0;
204 long LASTBOOKBUTTON=0;
205 long EXTERNALVIEW=0;
206 long ARX_CONVERSATION=0;
207 long ARX_CONVERSATION_MODE=-1;
208 long ARX_CONVERSATION_LASTIS=-1;
209 static long LAST_CONVERSATION = 0;
210 long SHOW_INGAME_MINIMAP= 1;
211 long NEED_TEST_TEXT=0;
212 static unsigned long FRAMETICKS=0;
213
214 float PLAYER_ARMS_FOCAL = 350.f;
215 float currentbeta=0.f;
216
217 unsigned char ARX_FLARES_Block=1;
218
219 Vec3f LASTCAMPOS;
220 Anglef LASTCAMANGLE;
221 Entity * CAMERACONTROLLER=NULL;
222 Entity *lastCAMERACONTROLLER=NULL;
223
224 // ArxGame constructor. Sets attributes for the app.
ArxGame()225 ArxGame::ArxGame() : wasResized(false) { }
226
~ArxGame()227 ArxGame::~ArxGame() {
228 }
229
Initialize()230 bool ArxGame::Initialize() {
231
232 bool init = Application::Initialize();
233 if(!init) {
234 return false;
235 }
236
237 init = InitGameData();
238 if(!init) {
239 LogCritical << "Failed to initialize the game data.";
240 return false;
241 }
242
243 init = initLocalisation();
244 if(!init) {
245 LogCritical << "Failed to initialize the localisation subsystem.";
246 return false;
247 }
248
249 Create();
250
251 return true;
252 }
253
setFullscreen(bool fullscreen)254 void ArxGame::setFullscreen(bool fullscreen) {
255
256 if(fullscreen) {
257
258 RenderWindow::DisplayMode mode(config.video.resolution, config.video.bpp);
259 if(mode.resolution == Vec2i::ZERO) {
260 mode = GetWindow()->getDisplayModes().back();
261 }
262
263 // Clamp to a sane resolution!
264 mode.resolution.x = std::max(mode.resolution.x, s32(640));
265 mode.resolution.y = std::max(mode.resolution.y, s32(480));
266
267 GetWindow()->setFullscreenMode(mode.resolution, mode.depth);
268
269 } else {
270
271 // Clamp to a sane window size!
272 config.window.size.x = std::max(config.window.size.x, s32(640));
273 config.window.size.y = std::max(config.window.size.y, s32(480));
274
275 GetWindow()->setWindowSize(config.window.size);
276
277 }
278 }
279
initWindow(RenderWindow * window)280 bool ArxGame::initWindow(RenderWindow * window) {
281
282 arx_assert(m_MainWindow == NULL);
283
284 m_MainWindow = window;
285
286 if(!m_MainWindow->initializeFramework()) {
287 m_MainWindow = NULL;
288 return false;
289 }
290
291 // Register ourself as a listener for this window messages
292 m_MainWindow->addListener(this);
293 m_MainWindow->addRenderListener(this);
294
295 const RenderWindow::DisplayModes & modes = window->getDisplayModes();
296
297 RenderWindow::DisplayMode mode(config.video.resolution, config.video.bpp);
298
299 if(config.video.resolution == Vec2i::ZERO) {
300
301 // Use the largest available resolution.
302 mode = modes.back();
303
304 } else {
305
306 // Find the next best available fullscreen mode.
307 RenderWindow::DisplayModes::const_iterator i;
308 i = std::lower_bound(modes.begin(), modes.end(), mode);
309 if(i == modes.end()) {
310 mode = *modes.rbegin();
311 } else {
312 mode = *i;
313 }
314 if(config.video.resolution != mode.resolution || unsigned(config.video.bpp) != mode.depth) {
315 LogWarning << "Fullscreen mode " << config.video.resolution.x << 'x' << config.video.resolution.y << '@' << config.video.bpp << " not supported, using " << mode.resolution.x << 'x' << mode.resolution.y << '@' << mode.depth << " instead";
316 }
317
318 }
319
320 // Clamp to a sane resolution and window size!
321 mode.resolution.x = std::max(mode.resolution.x, s32(640));
322 mode.resolution.y = std::max(mode.resolution.y, s32(480));
323 config.window.size.x = std::max(config.window.size.x, s32(640));
324 config.window.size.y = std::max(config.window.size.y, s32(480));
325
326 Vec2i size = config.video.fullscreen ? mode.resolution : config.window.size;
327
328 if(!m_MainWindow->initialize(arx_version, size, config.video.fullscreen, mode.depth)) {
329 m_MainWindow = NULL;
330 return false;
331 }
332
333 if(GRenderer == NULL) {
334 // We could not initialize all resources in onRendererInit().
335 m_MainWindow = NULL;
336 return false;
337 }
338
339 if(!m_MainWindow->isFullScreen() && config.video.resolution != Vec2i::ZERO) {
340 config.video.resolution = mode.resolution;
341 }
342 config.video.bpp = mode.depth;
343
344 return true;
345 }
346
InitWindow()347 bool ArxGame::InitWindow() {
348
349 arx_assert(m_MainWindow == NULL);
350
351 bool autoFramework = (config.window.framework == "auto");
352
353 for(int i = 0; i < 2 && !m_MainWindow; i++) {
354 bool first = (i == 0);
355
356 bool matched = false;
357
358 #ifdef ARX_HAVE_SDL
359 if(!m_MainWindow && first == (autoFramework || config.window.framework == "SDL")) {
360 matched = true;
361 RenderWindow * window = new SDLWindow;
362 if(!initWindow(window)) {
363 delete window;
364 }
365 }
366 #endif
367
368 #ifdef ARX_HAVE_D3D9
369 if(!m_MainWindow && first == (autoFramework || config.window.framework == "D3D9")) {
370 matched = true;
371 RenderWindow * window = new D3D9Window;
372 if(!initWindow(window)) {
373 delete window;
374 }
375 }
376 #endif
377
378 if(first && !matched) {
379 LogError << "Unknown windowing framework: " << config.window.framework;
380 }
381 }
382
383 if(!m_MainWindow) {
384 LogCritical << "Graphics initialization failed.";
385 return false;
386 }
387
388 return true;
389 }
390
InitInput()391 bool ArxGame::InitInput() {
392
393 LogDebug("Input init");
394 bool init = ARX_INPUT_Init();
395 if(!init) {
396 LogCritical << "Input initialization failed.";
397 }
398
399 return init;
400 }
401
InitSound()402 bool ArxGame::InitSound() {
403
404 LogDebug("Sound init");
405 bool init = ARX_SOUND_Init();
406 if(!init) {
407 LogWarning << "Sound initialization failed.";
408 }
409
410 return true;
411 }
412
InitGameData()413 bool ArxGame::InitGameData() {
414
415 bool init = AddPaks();
416 if(!init) {
417 LogCritical << "Error loading pak files";
418 return false;
419 }
420
421 ARX_SOUND_LoadData();
422
423 savegames.update(true);
424
425 return init;
426 }
427
428 static const char * default_paks[][2] = {
429 { "data.pak", NULL },
430 { "loc.pak", "loc_default.pak" },
431 { "data2.pak", NULL },
432 { "sfx.pak", NULL },
433 { "speech.pak", "speech_default.pak" },
434 };
435
AddPaks()436 bool ArxGame::AddPaks() {
437
438 arx_assert(!resources);
439
440 resources = new PakReader;
441
442 // Load required pak files
443 std::vector<size_t> missing;
444 for(size_t i = 0; i < ARRAY_SIZE(default_paks); i++) {
445 if(resources->addArchive(fs::paths.find(default_paks[i][0]))) {
446 continue;
447 }
448 if(default_paks[i][1]
449 && resources->addArchive(fs::paths.find(default_paks[i][1]))) {
450 continue;
451 }
452 missing.push_back(i);
453 }
454
455 if(!missing.empty()) {
456
457 // Try to launch the data file installer on non-Windows systems
458 #if ARX_PLATFORM != ARX_PLATFORM_WIN32
459 int ret = system("nohup arx-install-data --gui >/dev/null 2>&1 &");
460 (void)ret; // we really don't care!
461 #endif
462
463 // Construct an informative error message about missing files
464 std::ostringstream oss;
465 oss << "Could not load required ";
466 oss << (missing.size() == 1 ? "file" : "files");
467 size_t length = oss.tellp();
468 for(size_t i = 0; i < missing.size(); i++) {
469 if(i != 0) {
470 if(i + 1 == missing.size()) {
471 oss << " and", length += 4;
472 } else {
473 oss << ",", length++;
474 }
475 }
476 size_t add = 1 + strlen(default_paks[missing[i]][0]) + 1;
477 if(default_paks[missing[i]][1]) {
478 add += 6 + strlen(default_paks[missing[i]][1]) + 2;
479 }
480 if(length + add > 75) {
481 oss << "\n ", length = add + 1;
482 } else {
483 oss << ' ', length += add + 1;
484 }
485 oss << '"' << default_paks[missing[i]][0] << '"';
486 if(default_paks[missing[i]][1]) {
487 oss << " (or \"" << default_paks[missing[i]][1] << "\")";
488 length += 3 + strlen(default_paks[missing[i]][1]) + 2;
489 }
490 }
491 oss << ".\n\nSearched in these locations:\n";
492 std::vector<fs::path> search = fs::paths.getSearchPaths();
493 BOOST_FOREACH(const fs::path & dir, search) {
494 oss << " * " << dir.string() << fs::path::dir_sep << "\n";
495 }
496 oss << "\nSee " << url::help_get_data;
497 oss << " and " << url::help_install_data << "\n";
498 oss << "\nThe search path can be adjusted with command-line parameters.\n";
499 #if ARX_PLATFORM != ARX_PLATFORM_WIN32
500 oss << "\nWe will now try to launch the data install script for you...\n";
501 #endif
502 LogCritical << oss.str();
503
504 return false;
505 }
506
507 // Load optional patch files
508 BOOST_REVERSE_FOREACH(const fs::path & base, fs::paths.data) {
509 resources->addFiles(base / "editor", "editor");
510 resources->addFiles(base / "game", "game");
511 resources->addFiles(base / "graph", "graph");
512 resources->addFiles(base / "localisation", "localisation");
513 resources->addFiles(base / "misc", "misc");
514 resources->addFiles(base / "sfx", "sfx");
515 resources->addFiles(base / "speech", "speech");
516 }
517
518 return true;
519 }
520
521 //*************************************************************************************
522 // Create()
523 //*************************************************************************************
Create()524 bool ArxGame::Create() {
525
526 return true;
527 }
528
onWindowGotFocus(const Window &)529 void ArxGame::onWindowGotFocus(const Window &) {
530
531 if(GInput) {
532 GInput->reset();
533 GInput->unacquireDevices();
534 GInput->acquireDevices();
535 }
536 }
537
onWindowLostFocus(const Window &)538 void ArxGame::onWindowLostFocus(const Window &) {
539
540 if(GInput) {
541 GInput->unacquireDevices();
542 }
543 }
544
onResizeWindow(const Window & window)545 void ArxGame::onResizeWindow(const Window & window) {
546
547 arx_assert(window.getSize() != Vec2i::ZERO);
548
549 // A new window size will require a new backbuffer
550 // size, so the 3D structures must be changed accordingly.
551 wasResized = true;
552
553 if(window.isFullScreen()) {
554 if(config.video.resolution == Vec2i::ZERO) {
555 LogInfo << "Auto-selected fullscreen resolution " << window.getSize().x << 'x' << window.getSize().y << '@' << window.getDepth();
556 } else {
557 LogInfo << "Changed fullscreen resolution to " << window.getSize().x << 'x' << window.getSize().y << '@' << window.getDepth();
558 config.video.resolution = window.getSize();
559 }
560 } else {
561 LogInfo << "Changed window size to " << window.getSize().x << 'x' << window.getSize().y;
562 config.window.size = window.getSize();
563 }
564 }
565
onPaintWindow(const Window & window)566 void ArxGame::onPaintWindow(const Window& window)
567 {
568 ARX_UNUSED(window);
569 }
570
onDestroyWindow(const Window &)571 void ArxGame::onDestroyWindow(const Window &) {
572
573 LogInfo << "Application window is being destroyed";
574 Quit();
575 }
576
onToggleFullscreen(const Window & window)577 void ArxGame::onToggleFullscreen(const Window & window) {
578 config.video.fullscreen = window.isFullScreen();
579 GInput->reset();
580 wasResized = true;
581 }
582
583 //*************************************************************************************
584 // Run()
585 // Message-processing loop. Idle time is used to render the scene.
586 //*************************************************************************************
Run()587 void ArxGame::Run() {
588
589 BeforeRun();
590
591 while(m_RunLoop) {
592
593 m_MainWindow->tick();
594 if(!m_RunLoop) {
595 break;
596 }
597
598 if(m_MainWindow->hasFocus() && m_bReady) {
599 Render3DEnvironment();
600 }
601 }
602 }
603
604 //*************************************************************************************
605 // FrameMove()
606 // Called once per frame.
607 //*************************************************************************************
FrameMove()608 void ArxGame::FrameMove() {
609
610 if(!WILL_LAUNCH_CINE.empty()) {
611 // A cinematic is waiting to be played...
612 LaunchWaitingCine();
613 }
614 }
615
616 //*************************************************************************************
617 // Render3DEnvironment()
618 // Draws the scene.
619 //*************************************************************************************
Render3DEnvironment()620 void ArxGame::Render3DEnvironment() {
621
622 FrameMove();
623
624 Render();
625
626 // Show the frame on the primary surface.
627 GetWindow()->showFrame();
628 }
629
630 //*************************************************************************************
631 // Cleanup3DEnvironment()
632 // Cleanup scene objects
633 //*************************************************************************************
Cleanup3DEnvironment()634 void ArxGame::Cleanup3DEnvironment() {
635
636 if(GetWindow()) {
637 FinalCleanup();
638 }
639
640 }
641
642 //*************************************************************************************
643 // OutputText()
644 // Draws text on the window.
645 //*************************************************************************************
OutputText(int x,int y,const string & str)646 void ArxGame::OutputText(int x, int y, const string & str) {
647 if (m_bReady) {
648 hFontInGame->draw(x, y, str, Color(255, 255, 0));
649 }
650 }
651
652 //*************************************************************************************
653 // OutputText()
654 // Draws text on the window using selected font and color
655 // at position defined by column,row.
656 //*************************************************************************************
OutputTextGrid(float column,float row,const std::string & text,const Color & color)657 void ArxGame::OutputTextGrid(float column, float row, const std::string &text, const Color &color)
658 {
659 Font *selected_font = hFontInGame;
660
661 // find display size
662 const Vec2i &window = GetWindow()->getSize();
663
664 const int tsize = selected_font->getLineHeight();
665
666
667 // TODO: could use quadrants for width or something similar
668 // TODO: could center text in column/row
669 const Vector2<int> size(window.x / 4, selected_font->getLineHeight());
670
671 const Vector2<int> spacing(2, 2);
672 const Vector2<float> p(column + (column < 0), row + (row < 0));
673
674 // offset text into the screen a bit
675 const Vector2<int> offset((column < 0 ? window.x - tsize - size.x : tsize), (row < 0 ? window.y - tsize - size.y : tsize));
676
677 // print the text directly using our selected font
678 selected_font->draw(offset + Vector2<int>(p.x * (size + spacing).x, p.y * (size + spacing).y), text, color);
679
680 }
681
BeforeRun()682 bool ArxGame::BeforeRun() {
683
684 LogDebug("Before Run...");
685
686 const Vec2i & size = GetWindow()->getSize();
687 ControlCinematique = new Cinematic(size.x, size.y);
688
689 memset(&necklace,0,sizeof(ARX_NECKLACE));
690
691 long old = GLOBAL_EERIETEXTUREFLAG_LOADSCENE_RELEASE;
692 GLOBAL_EERIETEXTUREFLAG_LOADSCENE_RELEASE = -1;
693
694 necklace.lacet = loadObject("graph/interface/book/runes/lacet.teo");
695
696 necklace.runes[RUNE_AAM] = loadObject("graph/interface/book/runes/runes_aam.teo");
697 necklace.runes[RUNE_CETRIUS] = loadObject("graph/interface/book/runes/runes_citrius.teo");
698 necklace.runes[RUNE_COMUNICATUM] = loadObject("graph/interface/book/runes/runes_comunicatum.teo");
699 necklace.runes[RUNE_COSUM] = loadObject("graph/interface/book/runes/runes_cosum.teo");
700 necklace.runes[RUNE_FOLGORA] = loadObject("graph/interface/book/runes/runes_folgora.teo");
701 necklace.runes[RUNE_FRIDD] = loadObject("graph/interface/book/runes/runes_fridd.teo");
702 necklace.runes[RUNE_KAOM] = loadObject("graph/interface/book/runes/runes_kaom.teo");
703 necklace.runes[RUNE_MEGA] = loadObject("graph/interface/book/runes/runes_mega.teo");
704 necklace.runes[RUNE_MORTE] = loadObject("graph/interface/book/runes/runes_morte.teo");
705 necklace.runes[RUNE_MOVIS] = loadObject("graph/interface/book/runes/runes_movis.teo");
706 necklace.runes[RUNE_NHI] = loadObject("graph/interface/book/runes/runes_nhi.teo");
707 necklace.runes[RUNE_RHAA] = loadObject("graph/interface/book/runes/runes_rhaa.teo");
708 necklace.runes[RUNE_SPACIUM] = loadObject("graph/interface/book/runes/runes_spacium.teo");
709 necklace.runes[RUNE_STREGUM] = loadObject("graph/interface/book/runes/runes_stregum.teo");
710 necklace.runes[RUNE_TAAR] = loadObject("graph/interface/book/runes/runes_taar.teo");
711 necklace.runes[RUNE_TEMPUS] = loadObject("graph/interface/book/runes/runes_tempus.teo");
712 necklace.runes[RUNE_TERA] = loadObject("graph/interface/book/runes/runes_tera.teo");
713 necklace.runes[RUNE_VISTA] = loadObject("graph/interface/book/runes/runes_vista.teo");
714 necklace.runes[RUNE_VITAE] = loadObject("graph/interface/book/runes/runes_vitae.teo");
715 necklace.runes[RUNE_YOK] = loadObject("graph/interface/book/runes/runes_yok.teo");
716
717 necklace.pTexTab[RUNE_AAM] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_aam[icon]");
718 necklace.pTexTab[RUNE_CETRIUS] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_cetrius[icon]");
719 necklace.pTexTab[RUNE_COMUNICATUM] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_comunicatum[icon]");
720 necklace.pTexTab[RUNE_COSUM] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_cosum[icon]");
721 necklace.pTexTab[RUNE_FOLGORA] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_folgora[icon]");
722 necklace.pTexTab[RUNE_FRIDD] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_fridd[icon]");
723 necklace.pTexTab[RUNE_KAOM] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_kaom[icon]");
724 necklace.pTexTab[RUNE_MEGA] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_mega[icon]");
725 necklace.pTexTab[RUNE_MORTE] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_morte[icon]");
726 necklace.pTexTab[RUNE_MOVIS] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_movis[icon]");
727 necklace.pTexTab[RUNE_NHI] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_nhi[icon]");
728 necklace.pTexTab[RUNE_RHAA] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_rhaa[icon]");
729 necklace.pTexTab[RUNE_SPACIUM] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_spacium[icon]");
730 necklace.pTexTab[RUNE_STREGUM] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_stregum[icon]");
731 necklace.pTexTab[RUNE_TAAR] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_taar[icon]");
732 necklace.pTexTab[RUNE_TEMPUS] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_tempus[icon]");
733 necklace.pTexTab[RUNE_TERA] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_tera[icon]");
734 necklace.pTexTab[RUNE_VISTA] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_vista[icon]");
735 necklace.pTexTab[RUNE_VITAE] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_vitae[icon]");
736 necklace.pTexTab[RUNE_YOK] = TextureContainer::LoadUI("graph/obj3d/interactive/items/magic/rune_aam/rune_yok[icon]");
737
738 for(size_t i = 0; i < RUNE_COUNT-1; i++) { // TODO why -1?
739 if(necklace.pTexTab[i]) {
740 necklace.pTexTab[i]->getHalo();
741 }
742 }
743
744 EERIE_3DOBJ * _fogobj = LoadTheObj("editor/obj3d/fog_generator.teo", "node_teo maps");
745 ARX_FOGS_Set_Object(_fogobj);
746
747 eyeballobj = LoadTheObj("editor/obj3d/eyeball.teo", "eyeball_teo maps");
748 cabal = LoadTheObj("editor/obj3d/cabal.teo", "cabal_teo maps");
749 nodeobj = LoadTheObj("editor/obj3d/node.teo", "node_teo maps");
750
751 cameraobj = loadObject("graph/obj3d/interactive/system/camera/camera.teo");
752 markerobj = loadObject("graph/obj3d/interactive/system/marker/marker.teo");
753 arrowobj = loadObject("graph/obj3d/interactive/items/weapons/arrow/arrow.teo");
754
755 for(size_t i = 0; i < MAX_GOLD_COINS_VISUALS; i++) {
756
757 std::ostringstream oss;
758
759 if(i == 0) {
760 oss << "graph/obj3d/interactive/items/jewelry/gold_coin/gold_coin.teo";
761 } else {
762 oss << "graph/obj3d/interactive/items/jewelry/gold_coin/gold_coin" << (i + 1) << ".teo";
763 }
764
765 GoldCoinsObj[i] = loadObject(oss.str());
766
767 oss.str(string());
768
769 if(i == 0) {
770 oss << "graph/obj3d/interactive/items/jewelry/gold_coin/gold_coin[icon]";
771 } else {
772 oss << "graph/obj3d/interactive/items/jewelry/gold_coin/gold_coin" << (i + 1) << "[icon]";
773 }
774
775 GoldCoinsTC[i] = TextureContainer::LoadUI(oss.str());
776 }
777
778 Movable = TextureContainer::LoadUI("graph/interface/cursors/wrong");
779 ChangeLevel = TextureContainer::LoadUI("graph/interface/icons/change_lvl");
780
781 ARX_PLAYER_LoadHeroAnimsAndMesh();
782
783 GLOBAL_EERIETEXTUREFLAG_LOADSCENE_RELEASE = old;
784
785 return true;
786 }
787
Render()788 void ArxGame::Render() {
789
790 arxtime.update_frame_time();
791
792 // before modulation by "GLOBAL_SLOWDOWN"
793 Original_framedelay = arxtime.get_frame_delay();
794 arx_assert(Original_framedelay >= 0.0f);
795
796 // TODO this code shouldn't exist. ARXStartTime should be constant.
797 if (GLOBAL_SLOWDOWN != 1.0f)
798 {
799 arxtime.increment_start_time((u64)(Original_framedelay * (1.0f - GLOBAL_SLOWDOWN) * 1000.0f));
800
801 // recalculate frame delta
802 arxtime.update_frame_time();
803 }
804
805 framedelay = arxtime.get_frame_delay();
806 arx_assert(framedelay >= 0.0f);
807
808 // limit fps above 10fps
809 const float max_framedelay = 1000.0f / 10.0f;
810 framedelay = framedelay > max_framedelay ? max_framedelay : framedelay;
811
812 // TODO eliminate FrameDiff == framedelay (replace)
813 FrameDiff = framedelay;
814
815 if (GInput->isKeyPressedNowPressed(Keyboard::Key_F12))
816 {
817 EERIE_PORTAL_ReleaseOnlyVertexBuffer();
818 ComputePortalVertexBuffer();
819 }
820
821 ACTIVECAM = &subj;
822
823 if(wasResized) {
824 LogDebug("was resized");
825 wasResized = false;
826 DanaeRestoreFullScreen();
827 }
828
829 // Update input
830 GInput->update();
831 ReMappDanaeButton();
832 AdjustMousePosition();
833
834 // Manages Splash Screens if needed
835 if (DANAE_ManageSplashThings())
836 {
837 goto norenderend;
838 }
839
840 // Clicked on New Quest ? (TODO:need certainly to be moved somewhere else...)
841 if (START_NEW_QUEST)
842 {
843 LogDebug("start quest");
844 DANAE_StartNewQuest();
845 }
846
847 // Update Various Player Infos for this frame.
848 if (FirstFrame==0)
849 ARX_PLAYER_Frame_Update();
850
851 // Are we being teleported ?
852 if ((TELEPORT_TO_LEVEL[0]) && (CHANGE_LEVEL_ICON==200))
853 {
854 LogDebug("teleport to " << TELEPORT_TO_LEVEL << " " << TELEPORT_TO_POSITION << " "
855 << TELEPORT_TO_ANGLE);
856 CHANGE_LEVEL_ICON=-1;
857 ARX_CHANGELEVEL_Change(TELEPORT_TO_LEVEL, TELEPORT_TO_POSITION, TELEPORT_TO_ANGLE);
858 memset(TELEPORT_TO_LEVEL,0,64);
859 memset(TELEPORT_TO_POSITION,0,64);
860 }
861
862 subj.center = Vec2i(DANAECENTERX, DANAECENTERY);
863 subj.pos2 = subj.transform.mod = subj.center.to<float>();
864
865 // Finally computes current focal
866 BASE_FOCAL=(float)CURRENT_BASE_FOCAL+(BOW_FOCAL*( 1.0f / 4 ));
867
868 // SPECIFIC code for Snapshot MODE... to insure constant capture framerate
869
870 PULSATE=EEsin(arxtime.get_frame_time() / 800);
871 EERIEDrawnPolys=0;
872
873 // EditMode Specific code
874 if (EDITMODE)
875 {
876 TOTIOPDL=0;
877 BLOCK_PLAYER_CONTROLS=0;
878 }
879
880 if (FirstFrame==0) // Checks for Keyboard & Moulinex
881 {
882 ARX_MOUSE_OVER=0;
883
884 if (!EDITMODE && (ARXmenu.currentmode == AMCM_OFF)) // Playing Game
885 {
886 // Checks Clicks in Book Interface
887 if (ARX_INTERFACE_MouseInBook())
888 {
889 ARX_MOUSE_OVER|=ARX_MOUSE_OVER_BOOK;
890 LASTBOOKBUTTON=BOOKBUTTON;
891 BOOKBUTTON=EERIEMouseButton;
892
893 if ( ((EERIEMouseButton & 1) && !(LastMouseClick & 1) )
894 || ((EERIEMouseButton & 2) && !(LastMouseClick & 2) ) )
895 {
896 bookclick = DANAEMouse;
897 }
898 }
899 else if (InSecondaryInventoryPos(&DANAEMouse))
900 ARX_MOUSE_OVER|=ARX_MOUSE_OVER_INVENTORY_2;
901 else if (InPlayerInventoryPos(&DANAEMouse))
902 ARX_MOUSE_OVER|=ARX_MOUSE_OVER_INVENTORY;
903 }
904
905 if ( (player.Interface & INTER_COMBATMODE)
906 || (PLAYER_MOUSELOOK_ON) )
907 {
908 FlyingOverIO = NULL; // Avoid to check with those modes
909 }
910 else
911 {
912 if ((DRAGINTER == NULL) && (FRAME_COUNT<=0))
913 {
914 if (!BLOCK_PLAYER_CONTROLS && !TRUE_PLAYER_MOUSELOOK_ON && !(ARX_MOUSE_OVER & ARX_MOUSE_OVER_BOOK)
915 && (eMouseState != MOUSE_IN_NOTE)
916 )
917 FlyingOverIO = FlyingOverObject(&DANAEMouse);
918 else
919 FlyingOverIO = NULL;
920 }
921 }
922
923 if ( (!PLAYER_PARALYSED)
924 || (ARXmenu.currentmode != AMCM_OFF) )
925
926 {
927 if (!STOP_KEYBOARD_INPUT)
928 ManageKeyMouse();
929 else
930 {
931 STOP_KEYBOARD_INPUT++;
932
933 if (STOP_KEYBOARD_INPUT>2) STOP_KEYBOARD_INPUT=0;
934 }
935 }
936 }
937 else // Manages our first frameS
938 {
939 LogDebug("first frame");
940 arxtime.update();
941
942 FirstFrameHandling();
943 goto norenderend;
944 }
945
946 if(CheckInPolyPrecis(player.pos.x,player.pos.y,player.pos.z)) {
947 LastValidPlayerPos = player.pos;
948 }
949
950 // Updates Externalview
951 EXTERNALVIEW = 0;
952
953 GRenderer->SetRenderState(Renderer::Fog, false);
954
955 if(GInput->actionNowPressed(CONTROLS_CUST_TOGGLE_FULLSCREEN)) {
956 setFullscreen(!GetWindow()->isFullScreen());
957 }
958
959 if(ARX_Menu_Render()) {
960 goto norenderend;
961 }
962
963 if(WILL_QUICKSAVE) {
964 GRenderer->getSnapshot(savegame_thumbnail, 160, 100);
965 if(WILL_QUICKSAVE >= 2) {
966 ARX_QuickSave();
967 WILL_QUICKSAVE=0;
968 }
969 else WILL_QUICKSAVE++;
970 }
971
972 if (WILL_QUICKLOAD)
973 {
974 WILL_QUICKLOAD=0;
975
976 if (ARX_QuickLoad())
977 NEED_SPECIAL_RENDEREND=1;
978 }
979
980 if (NEED_SPECIAL_RENDEREND)
981 {
982 NEED_SPECIAL_RENDEREND=0;
983 goto norenderend;
984 }
985
986 GRenderer->SetRenderState(Renderer::Fog, true);
987 GRenderer->GetTextureStage(0)->SetWrapMode(TextureStage::WrapRepeat);
988
989 // Are we displaying a 2D cinematic ? Yes = manage it
990 if ( PLAY_LOADED_CINEMATIC
991 && ControlCinematique
992 && ControlCinematique->projectload)
993 {
994 if (DANAE_Manage_Cinematic()==1)
995 goto norenderend;
996
997 goto renderend;
998 }
999
1000 if (ARXmenu.currentmode == AMCM_OFF)
1001 {
1002 if (!PLAYER_PARALYSED)
1003 {
1004 if (ManageEditorControls()) goto finish;
1005 }
1006
1007 if ((!BLOCK_PLAYER_CONTROLS) && (!PLAYER_PARALYSED))
1008 {
1009 ManagePlayerControls();
1010 }
1011 }
1012
1013 ARX_PLAYER_Manage_Movement();
1014
1015 ARX_PLAYER_Manage_Visual();
1016
1017 if(FRAME_COUNT <= 0) {
1018 g_miniMap.setActiveBackground(ACTIVEBKG);
1019 g_miniMap.validatePlayerPos(CURRENTLEVEL, BLOCK_PLAYER_CONTROLS, Book_Mode);
1020 }
1021
1022 // SUBJECTIVE VIEW UPDATE START *********************************************************
1023 {
1024 // Clear screen & Z buffers
1025 if(desired.flags & GMOD_DCOLOR) {
1026 GRenderer->Clear(Renderer::ColorBuffer | Renderer::DepthBuffer, current.depthcolor.to<u8>());
1027 }
1028 else
1029 {
1030 subj.bkgcolor=ulBKGColor;
1031 GRenderer->Clear(Renderer::ColorBuffer | Renderer::DepthBuffer, subj.bkgcolor);
1032 }
1033
1034 //-------------------------------------------------------------------------------
1035 // DRAW CINEMASCOPE 16/9
1036 if(CINEMA_DECAL != 0.f) {
1037 Rect rectz[2];
1038 rectz[0].left = rectz[1].left = 0;
1039 rectz[0].right = rectz[1].right = DANAESIZX;
1040 rectz[0].top = 0;
1041 long lMulResult = checked_range_cast<long>(CINEMA_DECAL * Yratio);
1042 rectz[0].bottom = lMulResult;
1043 rectz[1].top = DANAESIZY - lMulResult;
1044 rectz[1].bottom = DANAESIZY;
1045 GRenderer->Clear(Renderer::ColorBuffer | Renderer::DepthBuffer, Color::none, 0.0f, 2, rectz);
1046 }
1047 //-------------------------------------------------------------------------------
1048
1049 GRenderer->BeginScene();
1050
1051 GRenderer->SetRenderState(Renderer::DepthWrite, true);
1052 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1053
1054 if ( (entities.player()) && (entities.player()->animlayer[0].cur_anim) )
1055 {
1056 ManageNONCombatModeAnimations();
1057 long old=USEINTERNORM;
1058 USEINTERNORM=0;
1059 float speedfactor;
1060 speedfactor=entities.player()->basespeed+entities.player()->speed_modif;
1061
1062 if (cur_mr==3) speedfactor+=0.5f;
1063
1064 if (cur_rf==3) speedfactor+=1.5f;
1065
1066 if (speedfactor < 0) speedfactor = 0;
1067
1068 long tFrameDiff = Original_framedelay;
1069
1070 if ((player.Interface & INTER_COMBATMODE) && (STRIKE_TIME))// need some precision for weapon...
1071 {
1072 float restore=ACTIVECAM->use_focal;
1073
1074 if ((!EXTERNALVIEW) && (!BOW_FOCAL))
1075 {
1076 ACTIVECAM->use_focal=PLAYER_ARMS_FOCAL*Xratio;
1077 }
1078
1079 float cur=0;
1080
1081 while ((cur<tFrameDiff) && (!(entities.player()->ioflags & IO_FREEZESCRIPT)))
1082 {
1083 long step=min(50L,tFrameDiff);
1084
1085 if (entities.player()->ioflags & IO_FREEZESCRIPT) step=0;
1086
1087
1088 float iCalc = step*speedfactor ;
1089
1090 arx_assert(entities.player()->obj != NULL);
1091 EERIEDrawAnimQuat(entities.player()->obj, &entities.player()->animlayer[0], &entities.player()->angle,
1092 &entities.player()->pos, checked_range_cast<unsigned long>(iCalc), entities.player(), false, false);
1093
1094 if ((player.Interface & INTER_COMBATMODE) && (entities.player()->animlayer[1].cur_anim != NULL))
1095 ManageCombatModeAnimations();
1096
1097 if (entities.player()->animlayer[1].cur_anim!=NULL)
1098 ManageCombatModeAnimationsEND();
1099
1100 cur+=step*speedfactor;
1101 }
1102
1103 ACTIVECAM->use_focal=restore;
1104 }
1105 else
1106 {
1107 float restore=ACTIVECAM->use_focal;
1108
1109 if ((!EXTERNALVIEW) && (!BOW_FOCAL))
1110 {
1111 ACTIVECAM->use_focal=PLAYER_ARMS_FOCAL*Xratio;
1112 }
1113
1114
1115 float val=(float)tFrameDiff*speedfactor;
1116
1117 if (entities.player()->ioflags & IO_FREEZESCRIPT) val=0;
1118
1119 arx_assert(entities.player()->obj != NULL);
1120 EERIEDrawAnimQuat(entities.player()->obj, &entities.player()->animlayer[0], &entities.player()->angle,
1121 &entities.player()->pos, checked_range_cast<unsigned long>(val), entities.player(), false, false);
1122
1123
1124 if ((player.Interface & INTER_COMBATMODE) && (entities.player()->animlayer[1].cur_anim != NULL))
1125 ManageCombatModeAnimations();
1126
1127 if (entities.player()->animlayer[1].cur_anim!=NULL)
1128 ManageCombatModeAnimationsEND();
1129
1130 ACTIVECAM->use_focal=restore;
1131 }
1132
1133 USEINTERNORM=old;
1134 }
1135
1136 Entity * io;
1137 io=entities.player();
1138 ANIM_USE * useanim;
1139 useanim=&io->animlayer[1];
1140 ANIM_HANDLE ** alist;
1141 alist=io->anims;
1142
1143 if ( BOW_FOCAL
1144 && (useanim->cur_anim!=alist[ANIM_MISSILE_STRIKE_PART_1])
1145 && (useanim->cur_anim!=alist[ANIM_MISSILE_STRIKE_PART_2])
1146 && (useanim->cur_anim!=alist[ANIM_MISSILE_STRIKE_CYCLE]))
1147 {
1148 BOW_FOCAL-=Original_framedelay;
1149
1150 if (BOW_FOCAL<0) BOW_FOCAL=0;
1151 }
1152
1153 if(eyeball.exist == 2) {
1154 subj.d_pos = eyeball.pos;
1155 subj.d_angle = eyeball.angle;
1156 EXTERNALVIEW = 1;
1157 }
1158 else if (EXTERNALVIEW)
1159 {
1160 float t=radians(player.angle.b);
1161 Vec3f tt;
1162
1163 for (long l=0;l<250;l+=10)
1164 {
1165 tt.x=player.pos.x+(float)EEsin(t)*(float)l;
1166 tt.y=player.pos.y-50.f;
1167 tt.z=player.pos.z-(float)EEcos(t)*(float)l;
1168 EERIEPOLY * ep = EECheckInPoly(&tt);
1169 if(ep) {
1170 subj.d_pos = tt;
1171 }
1172 else break;
1173 }
1174
1175 subj.d_angle.a=player.angle.a+30.f;
1176 subj.d_angle.b=player.angle.b;
1177 subj.d_angle.g=player.angle.g;
1178 EXTERNALVIEW=1;
1179
1180 } else {
1181
1182 subj.angle = player.angle;
1183 EXTERNALVIEW=0;
1184
1185 if(entities.player()) {
1186 long id = entities.player()->obj->fastaccess.view_attach;
1187 if(id != -1) {
1188 subj.pos = entities.player()->obj->vertexlist3[id].v;
1189 Vec3f vect;
1190 vect.x = subj.pos.x - player.pos.x;
1191 vect.y = 0;
1192 vect.z = subj.pos.z - player.pos.z;
1193 float len = ffsqrt(vect.lengthSqr());
1194 if(len > 46.f) {
1195 float div = 46.f / len;
1196 vect.x *= div;
1197 vect.z *= div;
1198 subj.pos.x=player.pos.x+vect.x;
1199 subj.pos.z=player.pos.z+vect.z;
1200 }
1201 } else {
1202 subj.pos = player.basePosition();
1203 }
1204 }
1205 }
1206
1207 if(EXTERNALVIEW) {
1208 subj.pos = (subj.pos + subj.d_pos) * 0.5f;
1209 subj.angle = interpolate(subj.angle, subj.d_angle, 0.1f);
1210 }
1211
1212 if ((ARX_CONVERSATION) && (main_conversation.actors_nb))
1213 {
1214 // Decides who speaks !!
1215 if (main_conversation.current<0)
1216 for (long j=0;j<main_conversation.actors_nb;j++)
1217 {
1218 if (main_conversation.actors[j]>=0)
1219 {
1220 for(size_t k = 0 ; k < MAX_ASPEECH; k++) {
1221 if (aspeech[k].exist)
1222 if (aspeech[k].io==entities[main_conversation.actors[j]])
1223 {
1224 main_conversation.current=k;
1225 j=main_conversation.actors_nb+1;
1226 k=MAX_ASPEECH+1;
1227 }
1228 }
1229 }
1230 }
1231
1232 long is=main_conversation.current;
1233
1234 if (ARX_CONVERSATION_LASTIS!=is) ARX_CONVERSATION_MODE=-1;
1235
1236 ARX_CONVERSATION_LASTIS=is;
1237
1238 if(ARX_CONVERSATION_MODE == -1) {
1239 ARX_CONVERSATION_MODE = 0;
1240 if(rnd() > 0.5f) {
1241 conversationcamera.size = Anglef(MAKEANGLE(170.f + rnd() * 20.f), 0.f, 0.f);
1242 conversationcamera.d_angle = Anglef(0.f, 0.f, 0.08f);
1243 } else {
1244 conversationcamera.size = Anglef(rnd() * 50.f, 0.f, rnd() * 50.f);
1245 conversationcamera.d_angle = Anglef::ZERO;
1246 if(rnd() > 0.4f) {
1247 conversationcamera.d_angle.a = (1.f - rnd() * 2.f) * (1.f / 30);
1248 }
1249 if(rnd() > 0.4f) {
1250 conversationcamera.d_angle.b = (1.f - rnd() * 1.2f) * 0.2f;
1251 }
1252 if(rnd() > 0.4f) {
1253 conversationcamera.d_angle.g = (1.f - rnd() * 2.f) * 0.025f;
1254 }
1255 }
1256 } else {
1257 conversationcamera.size += conversationcamera.d_angle * FrameDiff;
1258 }
1259
1260 Vec3f sourcepos,targetpos;
1261
1262 if(ApplySpeechPos(&conversationcamera, is)) {
1263 targetpos = conversationcamera.d_pos;
1264 sourcepos = conversationcamera.pos;
1265 } else {
1266 targetpos = player.pos;
1267 float t=radians(player.angle.b);
1268 sourcepos.x=targetpos.x+(float)EEsin(t)*100.f;
1269 sourcepos.y=targetpos.y;
1270 sourcepos.z=targetpos.z-(float)EEcos(t)*100.f;
1271 }
1272
1273 Vec3f vec2;
1274 Vec3f vect = targetpos - sourcepos;
1275 fnormalize(vect);
1276 float dist=250.f-conversationcamera.size.g;
1277
1278 if (dist<0.f) dist=(90.f-(dist*( 1.0f / 20 )));
1279 else if (dist<90.f) dist=90.f;
1280
1281 YRotatePoint(&vect,&vec2,EEcos(radians(conversationcamera.size.a)),EEsin(radians(conversationcamera.size.a)));
1282
1283 sourcepos = targetpos - vec2 * dist;
1284
1285 if (conversationcamera.size.b!=0.f)
1286 sourcepos.y+=120.f-conversationcamera.size.b*( 1.0f / 10 );
1287
1288 conversationcamera.pos = sourcepos;
1289 SetTargetCamera(&conversationcamera,targetpos.x,targetpos.y,targetpos.z);
1290 subj.pos = conversationcamera.pos;
1291 subj.angle.a = MAKEANGLE(-conversationcamera.angle.a);
1292 subj.angle.b = MAKEANGLE(conversationcamera.angle.b - 180.f);
1293 subj.angle.g = 0.f;
1294 EXTERNALVIEW = 1;
1295 }
1296 else
1297 {
1298 ARX_CONVERSATION_MODE=-1;
1299 ARX_CONVERSATION_LASTIS=-1;
1300
1301 if (LAST_CONVERSATION)
1302 {
1303 AcquireLastAnim(entities.player());
1304 ANIM_Set(&entities.player()->animlayer[1],entities.player()->anims[ANIM_WAIT]);
1305 entities.player()->animlayer[1].flags|=EA_LOOP;
1306 }
1307 }
1308
1309 ////////////////////////
1310 // Checks SCRIPT TIMERS.
1311 if (FirstFrame==0)
1312 ARX_SCRIPT_Timer_Check();
1313
1314 /////////////////////////////////////////////
1315 // Now checks for speech controlled cinematic
1316 {
1317 long valid=-1;
1318
1319 for(size_t i = 0; i < MAX_ASPEECH; i++) {
1320 if ((aspeech[i].exist) && (aspeech[i].cine.type>0))
1321 {
1322 valid=i;
1323 break;
1324 }
1325 }
1326
1327 if (valid>=0)
1328 {
1329 CinematicSpeech * acs=&aspeech[valid].cine;
1330 Entity * io=aspeech[valid].io;
1331 float rtime=(float)(arxtime.get_updated()-aspeech[valid].time_creation)/(float)aspeech[valid].duration;
1332
1333 if (rtime<0) rtime=0;
1334
1335 if (rtime>1) rtime=1;
1336
1337 float itime=1.f-rtime;
1338
1339 if ((rtime>=0.f) && (rtime<=1.f) && io)
1340 {
1341 float alpha,beta,distance,_dist;
1342
1343 switch (acs->type)
1344 {
1345 case ARX_CINE_SPEECH_KEEP: {
1346 subj.pos = acs->pos1;
1347 subj.angle.a=acs->pos2.x;
1348 subj.angle.b=acs->pos2.y;
1349 subj.angle.g=acs->pos2.z;
1350 EXTERNALVIEW=1;
1351 break;
1352 }
1353 case ARX_CINE_SPEECH_ZOOM: {
1354 //need to compute current values
1355 alpha=acs->startangle.a*itime+acs->endangle.a*rtime;
1356 beta=acs->startangle.b*itime+acs->endangle.b*rtime;
1357 distance=acs->startpos*itime+acs->endpos*rtime;
1358 Vec3f targetpos = acs->pos1;
1359 conversationcamera.pos.x=-EEsin(radians(MAKEANGLE(io->angle.b+beta)))*distance+targetpos.x;
1360 conversationcamera.pos.y= EEsin(radians(MAKEANGLE(io->angle.a+alpha)))*distance+targetpos.y;
1361 conversationcamera.pos.z= EEcos(radians(MAKEANGLE(io->angle.b+beta)))*distance+targetpos.z;
1362 SetTargetCamera(&conversationcamera,targetpos.x,targetpos.y,targetpos.z);
1363 subj.pos = conversationcamera.pos;
1364 subj.angle.a=MAKEANGLE(-conversationcamera.angle.a);
1365 subj.angle.b=MAKEANGLE(conversationcamera.angle.b-180.f);
1366 subj.angle.g=0.f;
1367 EXTERNALVIEW=1;
1368 break;
1369 }
1370 case ARX_CINE_SPEECH_SIDE_LEFT:
1371 case ARX_CINE_SPEECH_SIDE: {
1372
1373 if (ValidIONum(acs->ionum))
1374 {
1375
1376 const Vec3f & from = acs->pos1;
1377 const Vec3f & to = acs->pos2;
1378
1379 Vec3f vect = (to - from).getNormalized();
1380
1381 Vec3f vect2;
1382 if (acs->type==ARX_CINE_SPEECH_SIDE_LEFT)
1383 {
1384 Vector_RotateY(&vect2,&vect,-90);
1385 }
1386 else
1387 {
1388 Vector_RotateY(&vect2,&vect,90);
1389 }
1390
1391 distance=acs->f0*itime+acs->f1*rtime;
1392 vect2 *= distance;
1393 _dist = dist(from, to);
1394 Vec3f tfrom = from + vect * acs->startpos * (1.0f / 100) * _dist;
1395 Vec3f tto = from + vect * acs->endpos * (1.0f / 100) * _dist;
1396 Vec3f targetpos;
1397 targetpos.x=tfrom.x*itime+tto.x*rtime;
1398 targetpos.y=tfrom.y*itime+tto.y*rtime+acs->f2;
1399 targetpos.z=tfrom.z*itime+tto.z*rtime;
1400 conversationcamera.pos.x=targetpos.x+vect2.x;
1401 conversationcamera.pos.y=targetpos.y+vect2.y+acs->f2;
1402 conversationcamera.pos.z=targetpos.z+vect2.z;
1403 SetTargetCamera(&conversationcamera,targetpos.x,targetpos.y,targetpos.z);
1404 subj.pos = conversationcamera.pos;
1405 subj.angle.a=MAKEANGLE(-conversationcamera.angle.a);
1406 subj.angle.b=MAKEANGLE(conversationcamera.angle.b-180.f);
1407 subj.angle.g=0.f;
1408 EXTERNALVIEW=1;
1409 }
1410
1411 break;
1412 }
1413 case ARX_CINE_SPEECH_CCCLISTENER_R:
1414 case ARX_CINE_SPEECH_CCCLISTENER_L:
1415 case ARX_CINE_SPEECH_CCCTALKER_R:
1416 case ARX_CINE_SPEECH_CCCTALKER_L: {
1417
1418 //need to compute current values
1419 if (ValidIONum(acs->ionum))
1420 {
1421 Vec3f targetpos;
1422 if(acs->type == ARX_CINE_SPEECH_CCCLISTENER_L
1423 || acs->type == ARX_CINE_SPEECH_CCCLISTENER_R) {
1424 conversationcamera.pos = acs->pos2;
1425 targetpos = acs->pos1;
1426 } else {
1427 conversationcamera.pos = acs->pos1;
1428 targetpos = acs->pos2;
1429 }
1430
1431 distance=(acs->startpos*itime+acs->endpos*rtime)*( 1.0f / 100 );
1432
1433 Vec3f vect = conversationcamera.pos - targetpos;
1434 Vec3f vect2;
1435 Vector_RotateY(&vect2,&vect,90);
1436 vect2.normalize();
1437 Vec3f vect3 = vect.getNormalized();
1438
1439 vect = vect * distance + vect3 * 80.f;
1440 vect2 *= 45.f;
1441
1442 if ((acs->type==ARX_CINE_SPEECH_CCCLISTENER_R)
1443 || (acs->type==ARX_CINE_SPEECH_CCCTALKER_R))
1444 {
1445 vect2 = -vect2;
1446 }
1447
1448 conversationcamera.pos = vect + targetpos + vect2;
1449 SetTargetCamera(&conversationcamera,targetpos.x,targetpos.y,targetpos.z);
1450 subj.pos = conversationcamera.pos;
1451 subj.angle.a=MAKEANGLE(-conversationcamera.angle.a);
1452 subj.angle.b=MAKEANGLE(conversationcamera.angle.b-180.f);
1453 subj.angle.g=0.f;
1454 EXTERNALVIEW=1;
1455 }
1456
1457 break;
1458 }
1459 case ARX_CINE_SPEECH_NONE: break;
1460 }
1461
1462 LASTCAMPOS = subj.pos;
1463 LASTCAMANGLE = subj.angle;
1464 }
1465 }
1466 }
1467
1468 if (player.life<=0)
1469 {
1470 DeadTime += static_cast<long>(FrameDiff);
1471 float mdist = EEfabs(player.physics.cyl.height)-60;
1472 DeadCameraDistance+=(float)FrameDiff*( 1.0f / 80 )*((mdist-DeadCameraDistance)/mdist)*2.f;
1473
1474 if (DeadCameraDistance>mdist) DeadCameraDistance=mdist;
1475
1476 Vec3f targetpos = player.pos;
1477
1478 long id = entities.player()->obj->fastaccess.view_attach;
1479 long id2 = GetActionPointIdx( entities.player()->obj, "chest2leggings" );
1480
1481 if(id != -1) {
1482 targetpos = entities.player()->obj->vertexlist3[id].v;
1483 }
1484
1485 conversationcamera.pos.x = targetpos.x;
1486 conversationcamera.pos.y = targetpos.y - DeadCameraDistance;
1487 conversationcamera.pos.z = targetpos.z;
1488
1489 if (id2!=-1)
1490 {
1491 conversationcamera.pos.x=entities.player()->obj->vertexlist3[id2].v.x;
1492 conversationcamera.pos.y=entities.player()->obj->vertexlist3[id2].v.y-DeadCameraDistance;
1493 conversationcamera.pos.z=entities.player()->obj->vertexlist3[id2].v.z;
1494 }
1495
1496 SetTargetCamera(&conversationcamera,targetpos.x,targetpos.y,targetpos.z);
1497 subj.pos = conversationcamera.pos;
1498 subj.angle.a=MAKEANGLE(-conversationcamera.angle.a);
1499 subj.angle.b=MAKEANGLE(conversationcamera.angle.b-180.f);
1500 subj.angle.g = 0;
1501 EXTERNALVIEW=1;
1502
1503 BLOCK_PLAYER_CONTROLS = 1;
1504 }
1505 else
1506 {
1507 DeadCameraDistance=0;
1508
1509 }
1510
1511 /////////////////////////////////////
1512 LAST_CONVERSATION=ARX_CONVERSATION;
1513
1514 if (GInput->isKeyPressedNowPressed(Keyboard::Key_Spacebar) && (CAMERACONTROLLER!=NULL))
1515 CAMERACONTROLLER=NULL;
1516
1517 if (CAMERACONTROLLER!=NULL)
1518 {
1519 if (lastCAMERACONTROLLER!=CAMERACONTROLLER)
1520 {
1521 currentbeta=CAMERACONTROLLER->angle.b;
1522 }
1523
1524 Vec3f targetpos = CAMERACONTROLLER->pos + player.baseOffset();
1525
1526 float delta_angle = AngleDifference(currentbeta, CAMERACONTROLLER->angle.b);
1527 float delta_angle_t = delta_angle * FrameDiff * ( 1.0f / 1000 );
1528
1529 if (EEfabs(delta_angle_t) > EEfabs(delta_angle)) delta_angle_t = delta_angle;
1530
1531 currentbeta += delta_angle_t;
1532 float t=radians(MAKEANGLE(currentbeta));
1533 conversationcamera.pos.x=targetpos.x+(float)EEsin(t)*160.f;
1534 conversationcamera.pos.y=targetpos.y+40.f;
1535 conversationcamera.pos.z=targetpos.z-(float)EEcos(t)*160.f;
1536
1537 SetTargetCamera(&conversationcamera,targetpos.x,targetpos.y,targetpos.z);
1538 subj.pos = conversationcamera.pos;
1539 subj.angle.a=MAKEANGLE(-conversationcamera.angle.a);
1540 subj.angle.b=MAKEANGLE(conversationcamera.angle.b-180.f);
1541 subj.angle.g=0.f;
1542 EXTERNALVIEW=1;
1543 }
1544
1545 lastCAMERACONTROLLER=CAMERACONTROLLER;
1546
1547 if ((USE_CINEMATICS_CAMERA) && (USE_CINEMATICS_PATH.path!=NULL))
1548 {
1549 Vec3f pos,pos2;
1550 USE_CINEMATICS_PATH._curtime = arxtime.get_updated();
1551
1552 USE_CINEMATICS_PATH._curtime+=50;
1553 long pouet2=ARX_PATHS_Interpolate(&USE_CINEMATICS_PATH,&pos);
1554 USE_CINEMATICS_PATH._curtime-=50;
1555 long pouet=ARX_PATHS_Interpolate(&USE_CINEMATICS_PATH,&pos2);
1556
1557 if ((pouet!=-1) && (pouet2!=-1))
1558 {
1559 if(USE_CINEMATICS_CAMERA == 2) {
1560 subj.pos = pos;
1561 subj.d_angle = subj.angle;
1562 pos2 = (pos2 + pos) * (1.0f/2);
1563 SetTargetCamera(&subj, pos2.x, pos2.y, pos2.z);
1564 } else {
1565 DebugSphere(pos.x, pos.y, pos.z, 2, 50, Color::red);
1566 }
1567
1568 if (USE_CINEMATICS_PATH.aupflags & ARX_USEPATH_FLAG_FINISHED) // was .path->flags
1569 {
1570 USE_CINEMATICS_CAMERA=0;
1571 USE_CINEMATICS_PATH.path=NULL;
1572 }
1573 }
1574 else
1575 {
1576 USE_CINEMATICS_CAMERA=0;
1577 USE_CINEMATICS_PATH.path=NULL;
1578 }
1579 }
1580
1581 UpdateCameras();
1582
1583 ///////////////////////////////////////////
1584 ARX_PLAYER_FrameCheck(Original_framedelay);
1585
1586 if (MasterCamera.exist)
1587 {
1588 if (MasterCamera.exist & 2)
1589 {
1590 MasterCamera.exist&=~2;
1591 MasterCamera.exist|=1;
1592 MasterCamera.io=MasterCamera.want_io;
1593 MasterCamera.aup=MasterCamera.want_aup;
1594 MasterCamera.cam=MasterCamera.want_cam;
1595 }
1596
1597 if (MasterCamera.cam->focal<100.f) MasterCamera.cam->focal=350.f;
1598
1599 SetActiveCamera(MasterCamera.cam);
1600 EXTERNALVIEW=1;
1601 }
1602 else
1603 {
1604 // Set active camera for this viewport
1605 SetActiveCamera(&subj);
1606 }
1607
1608 ARX_GLOBALMODS_Apply();
1609
1610 if (EDITMODE) GRenderer->SetRenderState(Renderer::Fog, false);
1611
1612 ManageQuakeFX();
1613
1614 // Prepare ActiveCamera
1615 PrepareCamera(ACTIVECAM);
1616 // Recenter Viewport depending on Resolution
1617
1618 ACTIVECAM->center = Vec2i(DANAECENTERX, DANAECENTERY);
1619 ACTIVECAM->pos2 = ACTIVECAM->transform.mod = ACTIVECAM->center.to<float>();
1620
1621 // Set Listener Position
1622 {
1623 float t = radians(MAKEANGLE(ACTIVECAM->angle.b));
1624 Vec3f front(-EEsin(t), 0.f, EEcos(t));
1625 front.normalize();
1626 Vec3f up(0.f, 1.f, 0.f);
1627 ARX_SOUND_SetListener(&ACTIVECAM->pos, &front, &up);
1628 }
1629
1630 // Reset Transparent Polys Idx
1631 TRANSPOLYSPOS = 0;
1632
1633 // Check For Hiding/unHiding Player Gore
1634 if ((EXTERNALVIEW) || (player.life<=0))
1635 {
1636 ARX_INTERACTIVE_Show_Hide_1st(entities.player(),0);
1637 }
1638
1639 if (!EXTERNALVIEW)
1640 {
1641 ARX_INTERACTIVE_Show_Hide_1st(entities.player(),1);
1642 }
1643
1644 // NOW DRAW the player (Really...)
1645 if ( (entities.player())
1646 && (entities.player()->animlayer[0].cur_anim) )
1647 {
1648 float restore=ACTIVECAM->use_focal;
1649
1650 if ((!EXTERNALVIEW) && (!BOW_FOCAL))
1651 {
1652 ACTIVECAM->use_focal=PLAYER_ARMS_FOCAL*Xratio;
1653 }
1654
1655 if (!EXTERNALVIEW)
1656 FORCE_FRONT_DRAW=1;
1657
1658 if (entities.player()->invisibility>0.9f) entities.player()->invisibility=0.9f;
1659
1660 arx_assert(entities.player()->obj != NULL);
1661 EERIEDrawAnimQuat(entities.player()->obj, &entities.player()->animlayer[0], &entities.player()->angle,
1662 &entities.player()->pos, 0, entities.player());
1663
1664 ACTIVECAM->use_focal=restore;
1665 FORCE_FRONT_DRAW=0;
1666 }
1667
1668 // SUBJECTIVE VIEW UPDATE START *********************************************************
1669 GRenderer->SetRenderState(Renderer::DepthWrite, true);
1670 GRenderer->SetRenderState(Renderer::DepthTest, true);
1671
1672 if (FirstFrame==0)
1673 {
1674 PrepareIOTreatZone();
1675 ARX_PHYSICS_Apply();
1676
1677 if (FRAME_COUNT<=0)
1678 PrecalcIOLighting(&ACTIVECAM->pos, ACTIVECAM->cdepth * 0.6f);
1679
1680 ACTIVECAM->fadecolor = current.depthcolor;
1681
1682 if (uw_mode)
1683 {
1684 float val=10.f;
1685 GRenderer->GetTextureStage(0)->SetMipMapLODBias(val);
1686 ARX_SCENE_Render(1);
1687 val=-0.3f;
1688 GRenderer->GetTextureStage(0)->SetMipMapLODBias(val);
1689 } else {
1690 ARX_SCENE_Render(1);
1691 }
1692 }
1693
1694 // Begin Particles
1695
1696 if(pParticleManager) {
1697 pParticleManager->Update(static_cast<long>(FrameDiff));
1698 pParticleManager->Render();
1699 }
1700
1701 GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
1702 GRenderer->SetRenderState(Renderer::DepthWrite, false);
1703 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
1704 ARX_FOGS_Render();
1705
1706 ARX_PARTICLES_Render(&subj);
1707 UpdateObjFx();
1708
1709 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1710
1711 // End Particles
1712
1713 if (!EDITMODE) // Playing Game
1714 {
1715 // Checks Magic Flares Drawing
1716 if(!PLAYER_PARALYSED) {
1717 if(EERIEMouseButton & 1) {
1718 if(ARX_FLARES_Block == 0) {
1719 ARX_SPELLS_AddPoint(DANAEMouse);
1720 } else {
1721 CurrPoint = 0;
1722 ARX_FLARES_Block = 0;
1723 }
1724 } else if(ARX_FLARES_Block == 0) {
1725 ARX_FLARES_Block = 1;
1726 }
1727 }
1728
1729 ARX_SPELLS_Precast_Check();
1730 ARX_SPELLS_ManageMagic();
1731 ARX_SPELLS_UpdateSymbolDraw();
1732
1733 ManageTorch();
1734
1735 // Renders Magical Flares
1736 if ( !((player.Interface & INTER_MAP )
1737 && (!(player.Interface & INTER_COMBATMODE)))
1738 && flarenum
1739 )
1740 {
1741 ARX_MAGICAL_FLARES_Draw(FRAMETICKS);
1742 FRAMETICKS = (unsigned long)(arxtime);
1743 }
1744 }
1745 #ifdef BUILD_EDITOR
1746 else // EDITMODE == true
1747 {
1748 RenderAllNodes();
1749
1750 std::stringstream ss("EDIT MODE - Selected ");
1751 ss << NbIOSelected;
1752 ARX_TEXT_Draw(hFontInBook, 100, 2, ss.str(), Color::yellow);
1753
1754 if (EDITION==EDITION_FOGS)
1755 ARX_FOGS_RenderAll();
1756 }
1757 #endif
1758
1759 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
1760 GRenderer->SetRenderState(Renderer::DepthWrite, false);
1761
1762 // Checks some specific spell FX
1763 CheckMr();
1764
1765 if (Project.improve)
1766 DrawImproveVisionInterface();
1767 else
1768 {
1769 if ((subj.focal<BASE_FOCAL))
1770 {
1771 static const float INC_FOCAL = 75.0f;
1772 subj.focal+=INC_FOCAL;
1773
1774 if (subj.focal>BASE_FOCAL) subj.focal=BASE_FOCAL;
1775 }
1776 else if (subj.focal>BASE_FOCAL) subj.focal=BASE_FOCAL;
1777 }
1778
1779 if (eyeball.exist!=0)
1780 {
1781 DrawMagicSightInterface();
1782 }
1783
1784 if (PLAYER_PARALYSED)
1785 {
1786 GRenderer->SetRenderState(Renderer::DepthWrite, false);
1787 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
1788 GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
1789
1790 EERIEDrawBitmap(0.f, 0.f, (float)DANAESIZX, (float)DANAESIZY, 0.0001f, NULL, Color(71, 71, 255));
1791 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1792 GRenderer->SetRenderState(Renderer::DepthWrite, true);
1793 }
1794
1795 if (FADEDIR)
1796 {
1797 ManageFade();
1798 }
1799
1800 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1801 GRenderer->SetRenderState(Renderer::DepthWrite, true);
1802
1803 // Red screen fade for damages.
1804 ARX_DAMAGE_Show_Hit_Blood();
1805
1806 // Manage Notes/Books opened on screen
1807 GRenderer->SetRenderState(Renderer::Fog, false);
1808
1809 finish:; //----------------------------------------------------------------
1810 // Update spells
1811 ARX_SPELLS_Update();
1812
1813 GRenderer->SetCulling(Renderer::CullNone);
1814 GRenderer->SetRenderState(Renderer::Fog, true);
1815
1816 // Manage Death visual & Launch menu...
1817 if (DeadTime>2000)
1818 ARX_PLAYER_Manage_Death();
1819
1820 //-------------------------------------------------------------------------
1821
1822 // INTERFACE
1823 // Remove the Alphablend State if needed : NO Z Clear
1824 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1825 GRenderer->SetRenderState(Renderer::Fog, false);
1826
1827 // Draw game interface if needed
1828 if(ARXmenu.currentmode == AMCM_OFF && !CINEMASCOPE) {
1829
1830 GRenderer->GetTextureStage(0)->SetWrapMode(TextureStage::WrapClamp);
1831 GRenderer->SetRenderState(Renderer::DepthTest, false);
1832
1833 ARX_INTERFACE_NoteManage();
1834 DrawAllInterface();
1835 DrawAllInterfaceFinish();
1836
1837 if((player.Interface & INTER_MAP) && !(player.Interface & INTER_COMBATMODE)
1838 && flarenum) {
1839 ARX_MAGICAL_FLARES_Draw(FRAMETICKS);
1840 FRAMETICKS = (unsigned long)(arxtime);
1841 }
1842
1843 GRenderer->SetRenderState(Renderer::DepthTest, true);
1844 }
1845
1846 GRenderer->GetTextureStage(0)->SetWrapMode(TextureStage::WrapRepeat);
1847
1848 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1849 PopAllTriangleList();
1850 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
1851 PopAllTriangleListTransparency();
1852 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1853
1854 GRenderer->SetRenderState(Renderer::Fog, true);
1855 this->GoFor2DFX();
1856 GRenderer->SetRenderState(Renderer::Fog, false);
1857 GRenderer->Clear(Renderer::DepthBuffer);
1858
1859 // Speech Management
1860 if (!EDITMODE)
1861 {
1862 ARX_SPEECH_Check();
1863 ARX_SPEECH_Update();
1864 }
1865
1866 GRenderer->GetTextureStage(0)->SetWrapMode(TextureStage::WrapRepeat);
1867
1868 if(pTextManage && !pTextManage->Empty())
1869 {
1870 pTextManage->Update(FrameDiff);
1871 pTextManage->Render();
1872 }
1873
1874 if (SHOW_INGAME_MINIMAP && ((PLAY_LOADED_CINEMATIC == 0) && (!CINEMASCOPE) && (!BLOCK_PLAYER_CONTROLS) && (ARXmenu.currentmode == AMCM_OFF))
1875 && (!(player.Interface & INTER_MAP ) ))
1876 {
1877 long SHOWLEVEL = ARX_LEVELS_GetRealNum(CURRENTLEVEL);
1878
1879 if(SHOWLEVEL >= 0 && SHOWLEVEL < 32)
1880 g_miniMap.showPlayerMiniMap(SHOWLEVEL);
1881 }
1882
1883 //-------------------------------------------------------------------------
1884
1885 // CURSOR Rendering
1886 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1887
1888 if (DRAGINTER)
1889 {
1890 ARX_INTERFACE_RenderCursor();
1891
1892 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1893 PopAllTriangleList();
1894 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
1895 PopAllTriangleListTransparency();
1896 GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1897
1898 ARX_INTERFACE_HALO_Flush();
1899 }
1900 else
1901 {
1902 ARX_INTERFACE_HALO_Flush();
1903 ARX_INTERFACE_RenderCursor();
1904 }
1905
1906 GRenderer->SetRenderState(Renderer::Fog, true);
1907
1908 //----------------RENDEREND------------------------------------------------
1909 renderend:
1910 ;
1911
1912 if (sp_max_start)
1913 Manage_sp_max();
1914
1915 // Some Visual Debug/Info Text
1916 //CalcFPS();
1917
1918 if(NEED_TEST_TEXT) {
1919
1920 ShowTestText();
1921
1922 if(ViewMode & VIEWMODE_INFOTEXT) {
1923 ShowInfoText();
1924 }
1925
1926 if(USE_PORTALS) {
1927 char tex[250];
1928 switch(USE_PORTALS) {
1929 case 1:
1930 sprintf(tex, "2DPortals_ROOM: %ld", LAST_ROOM);
1931 break;
1932 case 2:
1933 sprintf(tex, "3DPortals_ROOM: %ld - Vis %ld", LAST_ROOM, LAST_PORTALS_COUNT);
1934 break;
1935 case 3:
1936 sprintf(tex, "3DPortals_ROOM(Transform): %ld - Vis %ld", LAST_ROOM, LAST_PORTALS_COUNT);
1937 break;
1938 case 4:
1939 sprintf(tex, "3DPortals_ROOM(TransformSC): %ld - Vis %ld", LAST_ROOM, LAST_PORTALS_COUNT);
1940 break;
1941 }
1942 OutputText( 320, 240, tex );
1943 }
1944
1945 if(bOLD_CLIPP) {
1946 OutputText(0, 240, "New Clipp");
1947 } else {
1948 OutputText(0, 274, "New Clipp");
1949 }
1950 }
1951
1952 //----------------------------------------------------------------------------
1953 // Begin 2D Pass for Lense Flares
1954
1955 if ((PLAY_LOADED_CINEMATIC == 0) && (!CINEMASCOPE) && (!BLOCK_PLAYER_CONTROLS) && (ARXmenu.currentmode == AMCM_OFF))
1956 {
1957 if (GInput->actionNowPressed(CONTROLS_CUST_QUICKLOAD) && !WILL_QUICKLOAD)
1958 {
1959 WILL_QUICKLOAD=1;
1960 }
1961
1962 if (GInput->actionNowPressed(CONTROLS_CUST_QUICKSAVE) && !WILL_QUICKSAVE)
1963 {
1964 iTimeToDrawD7=2000;
1965 WILL_QUICKSAVE=1;
1966 }
1967
1968 ARX_DrawAfterQuickLoad();
1969 }
1970
1971 GRenderer->EndScene();
1972
1973 //--------------NORENDEREND---------------------------------------------------
1974 norenderend:
1975
1976 if(GInput->isKeyPressedNowPressed(Keyboard::Key_F11)) {
1977 showFPS = !showFPS;
1978 }
1979
1980 if(showFPS) {
1981 GRenderer->BeginScene();
1982 CalcFPS();
1983 ShowFPS();
1984 GRenderer->EndScene();
1985 }
1986
1987 if(GInput->isKeyPressedNowPressed(Keyboard::Key_F10))
1988 {
1989 GetSnapShot();
1990 }
1991
1992 if ((LaunchDemo) && (FirstFrame == 0))
1993 {
1994 LaunchDemo=0;
1995 LaunchDummyParticle();
1996 }
1997 }
1998
1999 if (ARXmenu.currentmode == AMCM_OFF)
2000 {
2001 ARX_SCRIPT_AllowInterScriptExec();
2002 ARX_SCRIPT_EventStackExecute();
2003 // Updates Damages Spheres
2004 ARX_DAMAGES_UpdateAll();
2005 ARX_MISSILES_Update();
2006
2007 if (FirstFrame==0)
2008 ARX_PATH_UpdateAllZoneInOutInside();
2009 }
2010
2011 arxtime.update_last_frame_time();
2012 LastMouseClick=EERIEMouseButton;
2013 }
2014
GoFor2DFX()2015 void ArxGame::GoFor2DFX()
2016 {
2017 TexturedVertex lv,ltvv;
2018
2019 long needed = 0;
2020
2021 for (long i=0;i<TOTPDL;i++)
2022 {
2023 EERIE_LIGHT * el=PDL[i];
2024
2025 if (el->extras & EXTRAS_FLARE)
2026 {
2027 if(distSqr(ACTIVECAM->pos, el->pos) < square(2200)) {
2028 needed=1;
2029 break;
2030 }
2031 }
2032 }
2033
2034 if (!needed) return;
2035
2036 {
2037 Entity* pTableIO[256];
2038 int nNbInTableIO = 0;
2039
2040 float temp_increase=framedelay*( 1.0f / 1000 )*4.f;
2041 {
2042 bool bComputeIO = false;
2043
2044 for (int i=0;i<TOTPDL;i++)
2045 {
2046 EERIE_LIGHT * el=PDL[i];
2047
2048 long lPosx=(long)(float)(el->pos.x*ACTIVEBKG->Xmul);
2049 long lPosz=(long)(float)(el->pos.z*ACTIVEBKG->Zmul);
2050
2051 if( (lPosx<0)||
2052 (lPosx>=ACTIVEBKG->Xsize)||
2053 (lPosz<0)||
2054 (lPosz>=ACTIVEBKG->Zsize)||
2055 (!ACTIVEBKG->fastdata[lPosx][lPosz].treat) )
2056 {
2057 el->treat=0;
2058 continue;
2059 }
2060
2061 if (el->extras & EXTRAS_FLARE)
2062 {
2063 lv.p = el->pos;
2064 specialEE_RTP(&lv,<vv);
2065 el->temp-=temp_increase;
2066
2067 if (!(player.Interface & INTER_COMBATMODE)
2068 && (player.Interface & INTER_MAP))
2069 continue;
2070
2071 if ((ltvv.rhw > 0.f) &&
2072 (ltvv.p.x>0.f) &&
2073 (ltvv.p.y>(CINEMA_DECAL*Yratio)) &&
2074 (ltvv.p.x<DANAESIZX) &&
2075 (ltvv.p.y<(DANAESIZY-(CINEMA_DECAL*Yratio)))
2076 )
2077 {
2078 Vec3f vector = lv.p - ACTIVECAM->pos;
2079 lv.p -= vector * (50.f / vector.length());
2080 TexturedVertex ltvv2;
2081 specialEE_RTP(&lv, <vv2);
2082
2083 float fZFar=ProjectionMatrix._33*(1.f/(ACTIVECAM->cdepth*fZFogEnd))+ProjectionMatrix._43;
2084
2085 Vec3f hit;
2086 EERIEPOLY *tp=NULL;
2087 Vec2s ees2dlv;
2088 Vec3f ee3dlv = lv.p;
2089
2090 ees2dlv.x = checked_range_cast<short>(ltvv.p.x);
2091 ees2dlv.y = checked_range_cast<short>(ltvv.p.y);
2092
2093
2094 if( !bComputeIO )
2095 {
2096 GetFirstInterAtPos(&ees2dlv, 2, &ee3dlv, pTableIO, &nNbInTableIO );
2097 bComputeIO = true;
2098 }
2099
2100 if(
2101 (ltvv.p.z>fZFar)||
2102 EERIELaunchRay3(&ACTIVECAM->pos,&ee3dlv,&hit,tp,1)||
2103 GetFirstInterAtPos(&ees2dlv, 3, &ee3dlv, pTableIO, &nNbInTableIO )
2104 )
2105 {
2106 el->temp-=temp_increase*2.f;
2107 }
2108 else
2109 {
2110 el->temp+=temp_increase*2.f;
2111 }
2112
2113 }
2114
2115 if (el->temp<0.f) el->temp=0.f;
2116 else if (el->temp>.8f) el->temp=.8f;
2117 }
2118 }
2119 }
2120
2121 // End 2D Pass ***************************************************************************
2122
2123 {
2124 GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
2125 GRenderer->SetRenderState(Renderer::AlphaBlending, true);
2126 GRenderer->SetRenderState(Renderer::DepthWrite, false);
2127 GRenderer->SetCulling(Renderer::CullNone);
2128 GRenderer->SetRenderState(Renderer::DepthTest, false);
2129 GRenderer->SetFogColor(Color::none);
2130
2131 for (int i=0;i<TOTPDL;i++)
2132 {
2133 EERIE_LIGHT * el=PDL[i];
2134
2135 if ((!el->exist) || (!el->treat)) continue;
2136
2137 if (el->extras & EXTRAS_FLARE)
2138 {
2139 if (el->temp>0.f)
2140 {
2141 lv.p = el->pos;
2142 lv.rhw = 1.f;
2143 specialEE_RT(&lv, <vv.p);
2144 float v=el->temp;
2145
2146 if (FADEDIR)
2147 {
2148 v*=1.f-LAST_FADEVALUE;
2149 }
2150
2151 float siz;
2152
2153 if (el->extras & EXTRAS_FIXFLARESIZE)
2154 siz=el->ex_flaresize;
2155 else
2156 siz=-el->ex_flaresize;
2157
2158 EERIEDrawSprite(&lv, siz, tflare, (el->rgb * v).to<u8>(), ltvv.p.z);
2159
2160 }
2161 }
2162 }
2163
2164 GRenderer->SetRenderState(Renderer::DepthTest, true);
2165 }
2166 }
2167
2168 GRenderer->SetRenderState(Renderer::DepthWrite, true);
2169 }
2170
2171
InitDeviceObjects()2172 bool ArxGame::InitDeviceObjects() {
2173
2174 // Enable Z-buffering RenderState
2175 GRenderer->SetRenderState(Renderer::DepthTest, true);
2176
2177 // Restore All Textures RenderState
2178 GRenderer->RestoreAllTextures();
2179
2180 ARX_PLAYER_Restore_Skin();
2181
2182 // Disable Lighting RenderState
2183 GRenderer->SetRenderState(Renderer::Lighting, false);
2184
2185 // Setup Texture Border RenderState
2186 GRenderer->GetTextureStage(0)->SetWrapMode(TextureStage::WrapRepeat);
2187
2188 GRenderer->GetTextureStage(1)->DisableColor();
2189
2190 // Fog
2191 float fogEnd = 0.48f;
2192 float fogStart = fogEnd * 0.65f;
2193 GRenderer->SetFogParams(Renderer::FogLinear, fogStart, fogEnd);
2194 GRenderer->SetFogColor(current.depthcolor.to<u8>());
2195 GRenderer->SetRenderState(Renderer::Fog, true);
2196
2197 SetZBias(0);
2198
2199 ComputePortalVertexBuffer();
2200 VertexBuffer<SMY_VERTEX3> * vb3 = GRenderer->createVertexBuffer3(4000, Renderer::Stream);
2201 pDynamicVertexBuffer = new CircularVertexBuffer<SMY_VERTEX3>(vb3);
2202
2203 VertexBuffer<TexturedVertex> * vb = GRenderer->createVertexBufferTL(4000, Renderer::Stream);
2204 pDynamicVertexBuffer_TLVERTEX = new CircularVertexBuffer<TexturedVertex>(vb);
2205
2206 if(pMenu) {
2207 pMenu->bReInitAll=true;
2208 }
2209
2210 ARX_SetAntiAliasing();
2211
2212 return true;
2213 }
2214
2215 //*************************************************************************************
2216 // FinalCleanup()
2217 // Called before the app exits
2218 //*************************************************************************************
FinalCleanup()2219 bool ArxGame::FinalCleanup() {
2220
2221 EERIE_PATHFINDER_Release();
2222 ARX_INPUT_Release();
2223 ARX_SOUND_Release();
2224
2225 return true;
2226 }
2227
onRendererInit(RenderWindow & window)2228 void ArxGame::onRendererInit(RenderWindow & window) {
2229
2230 arx_assert(GRenderer == NULL);
2231
2232 GRenderer = window.getRenderer();
2233
2234 if(GRenderer->GetTextureStageCount() < 3) {
2235 LogError << "Arx Libertatis needs at least 3 texture units,"
2236 << " but only " << GRenderer->GetTextureStageCount() << " are available";
2237 GRenderer = NULL;
2238 return;
2239 }
2240
2241 InitDeviceObjects();
2242
2243 // The app is ready to go
2244 m_bReady = true;
2245 }
2246
onRendererShutdown(RenderWindow &)2247 void ArxGame::onRendererShutdown(RenderWindow &) {
2248
2249 if(!GRenderer) {
2250 // onRendererInit() failed
2251 return;
2252 }
2253
2254 m_bReady = false;
2255
2256 GRenderer->ReleaseAllTextures();
2257
2258 delete pDynamicVertexBuffer_TLVERTEX, pDynamicVertexBuffer_TLVERTEX = NULL;
2259 delete pDynamicVertexBuffer, pDynamicVertexBuffer = NULL;
2260
2261 EERIE_PORTAL_ReleaseOnlyVertexBuffer();
2262
2263 GRenderer = NULL;
2264 }
2265