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,&ltvv);
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, &ltvv2);
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, &ltvv.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