aboutsummaryrefslogtreecommitdiff
path: root/src/clientmap.h
Commit message (Collapse)AuthorAge
* Optimize/adjust blocks/ActiveObjects sent at the server based on client ↵lhofhansl2016-11-30
| | | | | | | settings. (#4811) Optimize/adjust blocks and active blocks sent at the server based on client settings.
* Add debug priv, and allow player to display the scene as wire-frame. (#4709)lhofhansl2016-11-04
|
* Camera: remove auto tune FPS, single view range settingRealBadAngel2016-02-21
|
* Clientmap: Define p_nodes_min/max as v3s32 instead of v3s16paramat2016-02-19
| | | | | | | | | 'cam_pos_nodes -/+ box_nodes_d' can exceed the range of v3s16 when a player is near the world edge using a large view range This previously caused world to disappear Create new function getBlocksInViewRange() called from updateDrawList() and renderMap() Correct code style throughout updateDrawList() and renderMap()
* v2d & aabbox3d<f32> & sky cleanupsnerzhul2016-02-11
| | | | | * Sky: rename Box => m_box and inline getBoundingBox * Uniformize aabbox3d<f32> to aabb3f
* Remove ClientMap::m_camera_mutexKahrl2016-02-09
| | | | | All places that lock this mutex are only called by the main thread: ClientMap::updateCamera(), ClientMap::updateDrawList(), ClientMap::renderMap(), ClientMap::renderPostFx().
* Clean up threadingShadowNinja2015-08-23
| | | | | | | | | | | | | | | | | | | | * Rename everything. * Strip J prefix. * Change UpperCamelCase functions to lowerCamelCase. * Remove global (!) semaphore count mutex on OSX. * Remove semaphore count getter (unused, unsafe, depended on internal API functions on Windows, and used a hack on OSX). * Add `Atomic<type>`. * Make `Thread` handle thread names. * Add support for C++11 multi-threading. * Combine pthread and win32 sources. * Remove `ThreadStarted` (unused, unneeded). * Move some includes from the headers to the sources. * Move all of `Event` into its header (allows inlining with no new includes). * Make `Event` use `Semaphore` (except on Windows). * Move some porting functions into `Thread`. * Integrate logging with `Thread`. * Add threading test.
* Performance of main client loop up to 2x faster In places, up to 3 times fasterCraig Robbins2014-12-07
| | | | | NOTE 1: This does not mean a 2x increase in framerate. Increase in fps may be up to 1-2fps NOTE 2: This local 'caching' of settings is not optimal and an alternative solution will be worked on after 0.4.11 is released
* Add support for interlaced polarized 3d screenssapier2014-05-18
| | | | Add (experimental) support for topbottom as well as sidebyside 3d mode
* Fix rendering glitches when far from the center of the mapNovatux2014-03-04
|
* Fix and improve view range tunerPerttu Ahola2013-08-03
|
* Migrate to STL containers/algorithms.Ilya Zhuravlev2013-03-11
|
* Update Copyright YearsSfan52013-02-24
|
* Change Minetest-c55 to MinetestPilzAdam2013-02-24
|
* Reorganize ClientMap rendering code for a bit more performancePerttu Ahola2012-09-04
| | | | | - Don't select blocks for drawing in every frame - Sort meshbuffers by material before drawing
* Optimize headersPerttu Ahola2012-06-17
|
* Switch the license to be LGPLv2/later, with small parts still remaining as ↵Perttu Ahola2012-06-05
| | | | GPLv2/later, by agreement of major contributors
* Dynamic sky, fog and cloud colors; sun and moonPerttu Ahola2012-03-18
|
* Move ClientMap to clientmap.{h,cpp}Perttu Ahola2012-03-16
393'>393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
#include "sky.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "S3DVertex.h"
#include "client/tile.h"
#include "noise.h"            // easeCurve
#include "profiler.h"
#include "util/numeric.h"
#include <cmath>
#include "settings.h"
#include "camera.h"           // CameraModes

//! constructor
Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id,
		ITextureSource *tsrc):
		scene::ISceneNode(parent, mgr, id),
		m_visible(true),
		m_fallback_bg_color(255,255,255,255),
		m_first_update(true),
		m_brightness(0.5),
		m_cloud_brightness(0.5),
		m_bgcolor_bright_f(1,1,1,1),
		m_skycolor_bright_f(1,1,1,1),
		m_cloudcolor_bright_f(1,1,1,1)
{
	setAutomaticCulling(scene::EAC_OFF);
	Box.MaxEdge.set(0,0,0);
	Box.MinEdge.set(0,0,0);

	// create material

	video::SMaterial mat;
	mat.Lighting = false;
	mat.ZBuffer = video::ECFN_NEVER;
	mat.ZWriteEnable = false;
	mat.AntiAliasing=0;
	mat.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
	mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
	mat.BackfaceCulling = false;

	m_materials[0] = mat;

	m_materials[1] = mat;
	//m_materials[1].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
	m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;

	m_materials[2] = mat;
	m_materials[2].setTexture(0, tsrc->getTextureForMesh("sunrisebg.png"));
	m_materials[2].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
	//m_materials[2].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;

	m_sun_texture = tsrc->isKnownSourceImage("sun.png") ?
		tsrc->getTextureForMesh("sun.png") : NULL;
	m_moon_texture = tsrc->isKnownSourceImage("moon.png") ?
		tsrc->getTextureForMesh("moon.png") : NULL;
	m_sun_tonemap = tsrc->isKnownSourceImage("sun_tonemap.png") ?
		tsrc->getTexture("sun_tonemap.png") : NULL;
	m_moon_tonemap = tsrc->isKnownSourceImage("moon_tonemap.png") ?
		tsrc->getTexture("moon_tonemap.png") : NULL;

	if (m_sun_texture){
		m_materials[3] = mat;
		m_materials[3].setTexture(0, m_sun_texture);
		m_materials[3].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
		if (m_sun_tonemap)
			m_materials[3].Lighting = true;
	}
	if (m_moon_texture){
		m_materials[4] = mat;
		m_materials[4].setTexture(0, m_moon_texture);
		m_materials[4].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
		if (m_moon_tonemap)
			m_materials[4].Lighting = true;
	}

	for(u32 i=0; i<SKY_STAR_COUNT; i++){
		m_stars[i] = v3f(
			myrand_range(-10000,10000),
			myrand_range(-10000,10000),
			myrand_range(-10000,10000)
		);
		m_stars[i].normalize();
	}

	m_directional_colored_fog = g_settings->getBool("directional_colored_fog");
}

void Sky::OnRegisterSceneNode()
{
	if (IsVisible)
		SceneManager->registerNodeForRendering(this, scene::ESNRP_SKY_BOX);

	scene::ISceneNode::OnRegisterSceneNode();
}

const core::aabbox3d<f32>& Sky::getBoundingBox() const
{
	return Box;
}

//! renders the node.
void Sky::render()
{
	if(!m_visible)
		return;

	video::IVideoDriver* driver = SceneManager->getVideoDriver();
	scene::ICameraSceneNode* camera = SceneManager->getActiveCamera();

	if (!camera || !driver)
		return;
	
	ScopeProfiler sp(g_profiler, "Sky::render()", SPT_AVG);

	// draw perspective skybox

	core::matrix4 translate(AbsoluteTransformation);
	translate.setTranslation(camera->getAbsolutePosition());

	// Draw the sky box between the near and far clip plane
	const f32 viewDistance = (camera->getNearValue() + camera->getFarValue()) * 0.5f;
	core::matrix4 scale;
	scale.setScale(core::vector3df(viewDistance, viewDistance, viewDistance));

	driver->setTransform(video::ETS_WORLD, translate * scale);

	if(m_sunlight_seen)
	{
		float sunsize = 0.07;
		video::SColorf suncolor_f(1, 1, 0, 1);
		suncolor_f.r = 1;
		suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.7+m_time_brightness*(0.5)));
		suncolor_f.b = MYMAX(0.0, m_brightness*0.95);
		video::SColorf suncolor2_f(1, 1, 1, 1);
		suncolor_f.r = 1;
		suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.85+m_time_brightness*(0.5)));
		suncolor_f.b = MYMAX(0.0, m_brightness);

		float moonsize = 0.04;
		video::SColorf mooncolor_f(0.50, 0.57, 0.65, 1);
		video::SColorf mooncolor2_f(0.85, 0.875, 0.9, 1);
		
		float nightlength = 0.415;
		float wn = nightlength / 2;
		float wicked_time_of_day = 0;
		if(m_time_of_day > wn && m_time_of_day < 1.0 - wn)
			wicked_time_of_day = (m_time_of_day - wn)/(1.0-wn*2)*0.5 + 0.25;
		else if(m_time_of_day < 0.5)
			wicked_time_of_day = m_time_of_day / wn * 0.25;
		else
			wicked_time_of_day = 1.0 - ((1.0-m_time_of_day) / wn * 0.25);
		/*std::cerr<<"time_of_day="<<m_time_of_day<<" -> "
				<<"wicked_time_of_day="<<wicked_time_of_day<<std::endl;*/

		video::SColor suncolor = suncolor_f.toSColor();
		video::SColor suncolor2 = suncolor2_f.toSColor();
		video::SColor mooncolor = mooncolor_f.toSColor();
		video::SColor mooncolor2 = mooncolor2_f.toSColor();

		// Calculate offset normalized to the X dimension of a 512x1 px tonemap
		float offset=(1.0-fabs(sin((m_time_of_day - 0.5)*irr::core::PI)))*511;

		if (m_sun_tonemap){
			u8 * texels = (u8 *)m_sun_tonemap->lock();
			video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4);
			video::SColor texel_color (255,texel->getRed(),texel->getGreen(), texel->getBlue());
			m_sun_tonemap->unlock();
			m_materials[3].EmissiveColor = texel_color;
		}
		if (m_moon_tonemap){
			u8 * texels = (u8 *)m_moon_tonemap->lock();
			video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4);
			video::SColor texel_color (255,texel->getRed(),texel->getGreen(), texel->getBlue());
			m_moon_tonemap->unlock();
			m_materials[4].EmissiveColor = texel_color;
		}

		const f32 t = 1.0f;
		const f32 o = 0.0f;
		static const u16 indices[4] = {0,1,2,3};
		video::S3DVertex vertices[4];
		
		driver->setMaterial(m_materials[1]);
		
		//video::SColor cloudyfogcolor(255,255,255,255);
		video::SColor cloudyfogcolor = m_bgcolor;
		//video::SColor cloudyfogcolor = m_bgcolor.getInterpolated(m_skycolor, 0.5);
		
		// Draw far cloudy fog thing
		for(u32 j=0; j<4; j++)
		{
			video::SColor c = cloudyfogcolor.getInterpolated(m_skycolor, 0.45);
			vertices[0] = video::S3DVertex(-1, 0.08,-1, 0,0,1, c, t, t);
			vertices[1] = video::S3DVertex( 1, 0.08,-1, 0,0,1, c, o, t);
			vertices[2] = video::S3DVertex( 1, 0.12,-1, 0,0,1, c, o, o);
			vertices[3] = video::S3DVertex(-1, 0.12,-1, 0,0,1, c, t, o);
			for(u32 i=0; i<4; i++){
				if(j==0)
					// Don't switch
					{}
				else if(j==1)
					// Switch from -Z (south) to +X (east)
					vertices[i].Pos.rotateXZBy(90);
				else if(j==2)
					// Switch from -Z (south) to -X (west)
					vertices[i].Pos.rotateXZBy(-90);
				else
					// Switch from -Z (south) to -Z (north)
					vertices[i].Pos.rotateXZBy(-180);
			}
			driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
		}
		for(u32 j=0; j<4; j++)
		{
			video::SColor c = cloudyfogcolor;
			vertices[0] = video::S3DVertex(-1,-1.0,-1, 0,0,1, c, t, t);
			vertices[1] = video::S3DVertex( 1,-1.0,-1, 0,0,1, c, o, t);
			vertices[2] = video::S3DVertex( 1, 0.08,-1, 0,0,1, c, o, o);
			vertices[3] = video::S3DVertex(-1, 0.08,-1, 0,0,1, c, t, o);
			for(u32 i=0; i<4; i++){
				if(j==0)
					// Don't switch
					{}
				else if(j==1)
					// Switch from -Z (south) to +X (east)
					vertices[i].Pos.rotateXZBy(90);
				else if(j==2)
					// Switch from -Z (south) to -X (west)
					vertices[i].Pos.rotateXZBy(-90);
				else
					// Switch from -Z (south) to -Z (north)
					vertices[i].Pos.rotateXZBy(-180);
			}
			driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
		}

		driver->setMaterial(m_materials[2]);

		{
			float mid1 = 0.25;
			float mid = (wicked_time_of_day < 0.5 ? mid1 : (1.0 - mid1));
			float a_ = 1.0 - fabs(wicked_time_of_day - mid) * 35.0;
			float a = easeCurve(MYMAX(0, MYMIN(1, a_)));
			//std::cerr<<"a_="<<a_<<" a="<<a<<std::endl;
			video::SColor c(255,255,255,255);
			float y = -(1.0 - a) * 0.2;
			vertices[0] = video::S3DVertex(-1,-0.05+y,-1, 0,0,1, c, t, t);
			vertices[1] = video::S3DVertex( 1,-0.05+y,-1, 0,0,1, c, o, t);
			vertices[2] = video::S3DVertex( 1, 0.2+y,-1, 0,0,1, c, o, o);
			vertices[3] = video::S3DVertex(-1, 0.2+y,-1, 0,0,1, c, t, o);
			for(u32 i=0; i<4; i++){
				if(wicked_time_of_day < 0.5)
					// Switch from -Z (south) to +X (east)
					vertices[i].Pos.rotateXZBy(90);
				else
					// Switch from -Z (south) to -X (west)
					vertices[i].Pos.rotateXZBy(-90);
			}
			driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
		}

		// Draw sun
		if(wicked_time_of_day > 0.15 && wicked_time_of_day < 0.85){
			if (!m_sun_texture){
				driver->setMaterial(m_materials[1]);
				float d = sunsize * 1.7;
				video::SColor c = suncolor;
				c.setAlpha(0.05*255);
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
				vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
				vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
				vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to +X (east)
					vertices[i].Pos.rotateXZBy(90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);

				d = sunsize * 1.2;
				c = suncolor;
				c.setAlpha(0.15*255);
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
				vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
				vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
				vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to +X (east)
					vertices[i].Pos.rotateXZBy(90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);

				d = sunsize;
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, suncolor, t, t);
				vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, suncolor, o, t);
				vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, suncolor, o, o);
				vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, suncolor, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to +X (east)
					vertices[i].Pos.rotateXZBy(90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);

				d = sunsize * 0.7;
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, suncolor2, t, t);
				vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, suncolor2, o, t);
				vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, suncolor2, o, o);
				vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, suncolor2, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to +X (east)
					vertices[i].Pos.rotateXZBy(90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
			} else {
				driver->setMaterial(m_materials[3]);
				float d = sunsize * 1.7;
				video::SColor c;
				if (m_sun_tonemap)
					c = video::SColor (0,0,0,0);
				else
					c = video::SColor (255,255,255,255);
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
				vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
				vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
				vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to +X (east)
					vertices[i].Pos.rotateXZBy(90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
			}
		}

		// Draw moon
		if(wicked_time_of_day < 0.3 || wicked_time_of_day > 0.7)
		{
			if (!m_moon_texture){
				driver->setMaterial(m_materials[1]);
				float d = moonsize * 1.9;
				video::SColor c = mooncolor;
				c.setAlpha(0.05*255);
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
				vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
				vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
				vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to -X (west)
					vertices[i].Pos.rotateXZBy(-90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
			
				d = moonsize * 1.3;
				c = mooncolor;
				c.setAlpha(0.15*255);
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
				vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
				vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
				vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to -X (west)
					vertices[i].Pos.rotateXZBy(-90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);

				d = moonsize;
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, mooncolor, t, t);
				vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, mooncolor, o, t);
				vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, mooncolor, o, o);
				vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, mooncolor, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to -X (west)
					vertices[i].Pos.rotateXZBy(-90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);

				float d2 = moonsize * 0.6;
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, mooncolor2, t, t);
				vertices[1] = video::S3DVertex( d2,-d,-1, 0,0,1, mooncolor2, o, t);
				vertices[2] = video::S3DVertex( d2, d2,-1, 0,0,1, mooncolor2, o, o);
				vertices[3] = video::S3DVertex(-d, d2,-1, 0,0,1, mooncolor2, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to -X (west)
					vertices[i].Pos.rotateXZBy(-90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
			} else {
				driver->setMaterial(m_materials[4]);
				float d = moonsize * 1.9;
				video::SColor c;
				if (m_moon_tonemap)
					c = video::SColor (0,0,0,0);
				else
					c = video::SColor (255,255,255,255);
				vertices[0] = video::S3DVertex(-d,-d,-1, 0,0,1, c, t, t);
				vertices[1] = video::S3DVertex( d,-d,-1, 0,0,1, c, o, t);
				vertices[2] = video::S3DVertex( d, d,-1, 0,0,1, c, o, o);
				vertices[3] = video::S3DVertex(-d, d,-1, 0,0,1, c, t, o);
				for(u32 i=0; i<4; i++){
					// Switch from -Z (south) to -X (west)
					vertices[i].Pos.rotateXZBy(-90);
					vertices[i].Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
				}
				driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
			}
		}

		// Stars
		driver->setMaterial(m_materials[1]);
		do{
			float starbrightness = MYMAX(0, MYMIN(1,
					(0.285 - fabs(wicked_time_of_day < 0.5 ?
					wicked_time_of_day : (1.0 - wicked_time_of_day))) * 10));
			float f = starbrightness;
			float d = 0.007;
			video::SColor starcolor(255, f*90,f*90,f*90);
			if(starcolor.getBlue() < m_skycolor.getBlue())
				break;
			u16 indices[SKY_STAR_COUNT*4];
			video::S3DVertex vertices[SKY_STAR_COUNT*4];
			for(u32 i=0; i<SKY_STAR_COUNT; i++){
				indices[i*4+0] = i*4+0;
				indices[i*4+1] = i*4+1;
				indices[i*4+2] = i*4+2;
				indices[i*4+3] = i*4+3;
				v3f p = m_stars[i];
				core::CMatrix4<f32> a;
				a.buildRotateFromTo(v3f(0,1,0), v3f(d,1+d/2,0));
				v3f p1 = p;
				a.rotateVect(p1);
				a.buildRotateFromTo(v3f(0,1,0), v3f(d,1,d));
				v3f p2 = p;
				a.rotateVect(p2);
				a.buildRotateFromTo(v3f(0,1,0), v3f(0,1-d/2,d));
				v3f p3 = p;
				a.rotateVect(p3);
				p.rotateXYBy(wicked_time_of_day * 360 - 90);
				p1.rotateXYBy(wicked_time_of_day * 360 - 90);
				p2.rotateXYBy(wicked_time_of_day * 360 - 90);
				p3.rotateXYBy(wicked_time_of_day * 360 - 90);
				vertices[i*4+0].Pos = p;
				vertices[i*4+0].Color = starcolor;
				vertices[i*4+1].Pos = p1;
				vertices[i*4+1].Color = starcolor;
				vertices[i*4+2].Pos = p2;
				vertices[i*4+2].Color = starcolor;
				vertices[i*4+3].Pos = p3;
				vertices[i*4+3].Color = starcolor;
			}
			driver->drawVertexPrimitiveList(vertices, SKY_STAR_COUNT*4,
					indices, SKY_STAR_COUNT, video::EVT_STANDARD,
					scene::EPT_QUADS, video::EIT_16BIT);
		}while(0);
		
		for(u32 j=0; j<2; j++)
		{
			//video::SColor c = m_skycolor;
			video::SColor c = cloudyfogcolor;
			vertices[0] = video::S3DVertex(-1,-1.0,-1, 0,0,1, c, t, t);
			vertices[1] = video::S3DVertex( 1,-1.0,-1, 0,0,1, c, o, t);
			vertices[2] = video::S3DVertex( 1,-0.02,-1, 0,0,1, c, o, o);
			vertices[3] = video::S3DVertex(-1,-0.02,-1, 0,0,1, c, t, o);
			for(u32 i=0; i<4; i++){
				//if(wicked_time_of_day < 0.5)
				if(j==0)
					// Switch from -Z (south) to +X (east)
					vertices[i].Pos.rotateXZBy(90);
				else
					// Switch from -Z (south) to -X (west)
					vertices[i].Pos.rotateXZBy(-90);
			}
			driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
		}
	}
}

void Sky::update(float time_of_day, float time_brightness,
		float direct_brightness, bool sunlight_seen,
		CameraMode cam_mode, float yaw, float pitch)
{
	// Stabilize initial brightness and color values by flooding updates
	if(m_first_update){
		/*dstream<<"First update with time_of_day="<<time_of_day
				<<" time_brightness="<<time_brightness
				<<" direct_brightness="<<direct_brightness
				<<" sunlight_seen="<<sunlight_seen<<std::endl;*/
		m_first_update = false;
		for(u32 i=0; i<100; i++){
			update(time_of_day, time_brightness, direct_brightness,
					sunlight_seen, cam_mode, yaw, pitch);
		}
		return;
	}

	m_time_of_day = time_of_day;
	m_time_brightness = time_brightness;
	m_sunlight_seen = sunlight_seen;
	
	bool is_dawn = (time_brightness >= 0.20 && time_brightness < 0.35);

	//video::SColorf bgcolor_bright_normal_f(170./255,200./255,230./255, 1.0);
	video::SColorf bgcolor_bright_normal_f(155./255,193./255,240./255, 1.0);
	video::SColorf bgcolor_bright_indoor_f(100./255,100./255,100./255, 1.0);
	//video::SColorf bgcolor_bright_dawn_f(0.666,200./255*0.7,230./255*0.5,1.0);
	//video::SColorf bgcolor_bright_dawn_f(0.666,0.549,0.220,1.0);
	//video::SColorf bgcolor_bright_dawn_f(0.666*1.2,0.549*1.0,0.220*1.0, 1.0);
	//video::SColorf bgcolor_bright_dawn_f(0.666*1.2,0.549*1.0,0.220*1.2,1.0);
	video::SColorf bgcolor_bright_dawn_f
			(155./255*1.2,193./255,240./255, 1.0);

	video::SColorf skycolor_bright_normal_f =
			video::SColor(255, 140, 186, 250);
	video::SColorf skycolor_bright_dawn_f =
			video::SColor(255, 180, 186, 250);
	
	video::SColorf cloudcolor_bright_normal_f =
			video::SColor(255, 240,240,255);
	//video::SColorf cloudcolor_bright_dawn_f(1.0, 0.591, 0.4);
	//video::SColorf cloudcolor_bright_dawn_f(1.0, 0.65, 0.44);
	//video::SColorf cloudcolor_bright_dawn_f(1.0, 0.7, 0.5);
	video::SColorf cloudcolor_bright_dawn_f(1.0, 0.875, 0.75);

	float cloud_color_change_fraction = 0.95;
	if(sunlight_seen){
		if(fabs(time_brightness - m_brightness) < 0.2){
			m_brightness = m_brightness * 0.95 + time_brightness * 0.05;
		} else {
			m_brightness = m_brightness * 0.80 + time_brightness * 0.20;
			cloud_color_change_fraction = 0.0;
		}
	}
	else{
		if(direct_brightness < m_brightness)
			m_brightness = m_brightness * 0.95 + direct_brightness * 0.05;
		else
			m_brightness = m_brightness * 0.98 + direct_brightness * 0.02;
	}
	
	m_clouds_visible = true;
	float color_change_fraction = 0.98;
	if(sunlight_seen){
		if(is_dawn){
			m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
					bgcolor_bright_dawn_f, color_change_fraction);
			m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
					skycolor_bright_dawn_f, color_change_fraction);
			m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
					cloudcolor_bright_dawn_f, color_change_fraction);
		} else {
			m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
					bgcolor_bright_normal_f, color_change_fraction);
			m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
					skycolor_bright_normal_f, color_change_fraction);
			m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
					cloudcolor_bright_normal_f, color_change_fraction);
		}
	} else {
		m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
				bgcolor_bright_indoor_f, color_change_fraction);
		m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
				bgcolor_bright_indoor_f, color_change_fraction);
		m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
				cloudcolor_bright_normal_f, color_change_fraction);
		m_clouds_visible = false;
	}

	video::SColor bgcolor_bright = m_bgcolor_bright_f.toSColor();
	m_bgcolor = video::SColor(
		255,
		bgcolor_bright.getRed() * m_brightness,
		bgcolor_bright.getGreen() * m_brightness,
		bgcolor_bright.getBlue() * m_brightness);

	video::SColor skycolor_bright = m_skycolor_bright_f.toSColor();
	m_skycolor = video::SColor(
		255,
		skycolor_bright.getRed() * m_brightness,
		skycolor_bright.getGreen() * m_brightness,
		skycolor_bright.getBlue() * m_brightness);

	// Horizon coloring based on sun and moon direction during sunset and sunrise
	video::SColor pointcolor = video::SColor(255, 255, 255, m_bgcolor.getAlpha());
	if (m_directional_colored_fog) {
		if (m_horizon_blend() != 0)
		{
			// calculate hemisphere value from yaw, (inverted in third person front view)
			s8 dir_factor = 1;
			if (cam_mode > CAMERA_MODE_THIRD)
				dir_factor = -1;
			f32 pointcolor_blend = wrapDegrees_0_360( yaw*dir_factor + 90);
			if (pointcolor_blend > 180)
				pointcolor_blend = 360 - pointcolor_blend;
			pointcolor_blend /= 180;
			// bound view angle to determine where transition starts and ends
			pointcolor_blend = rangelim(1 - pointcolor_blend * 1.375, 0, 1 / 1.375) * 1.375;
			// combine the colors when looking up or down, otherwise turning looks weird
			pointcolor_blend += (0.5 - pointcolor_blend) * (1 - MYMIN((90 - std::abs(pitch)) / 90 * 1.5, 1));
			// invert direction to match where the sun and moon are rising
			if (m_time_of_day > 0.5)
				pointcolor_blend = 1 - pointcolor_blend;
			// horizon colors of sun and moon
			f32 pointcolor_light = rangelim(m_time_brightness * 3, 0.2, 1);

			video::SColorf pointcolor_sun_f(1, 1, 1, 1);
			if (m_sun_tonemap)
			{
				pointcolor_sun_f.r = pointcolor_light * (float)m_materials[3].EmissiveColor.getRed() / 255;
				pointcolor_sun_f.b = pointcolor_light * (float)m_materials[3].EmissiveColor.getBlue() / 255;
				pointcolor_sun_f.g = pointcolor_light * (float)m_materials[3].EmissiveColor.getGreen() / 255;
			}
			else
			{
				pointcolor_sun_f.r = pointcolor_light * 1;
				pointcolor_sun_f.b = pointcolor_light * (0.25 + (rangelim(m_time_brightness, 0.25, 0.75) - 0.25) * 2 * 0.75);
				pointcolor_sun_f.g = pointcolor_light * (pointcolor_sun_f.b * 0.375 + (rangelim(m_time_brightness, 0.05, 0.15) - 0.05) * 10 * 0.625);
			}

			video::SColorf pointcolor_moon_f(0.5 * pointcolor_light, 0.6 * pointcolor_light, 0.8 * pointcolor_light, 1);
			if (m_moon_tonemap)
			{
				pointcolor_moon_f.r = pointcolor_light * (float)m_materials[4].EmissiveColor.getRed() / 255;
				pointcolor_moon_f.b = pointcolor_light * (float)m_materials[4].EmissiveColor.getBlue() / 255;
				pointcolor_moon_f.g = pointcolor_light * (float)m_materials[4].EmissiveColor.getGreen() / 255;
			}

			video::SColor pointcolor_sun = pointcolor_sun_f.toSColor();
			video::SColor pointcolor_moon = pointcolor_moon_f.toSColor();
			// calculate the blend color
			pointcolor = m_mix_scolor(pointcolor_moon, pointcolor_sun, pointcolor_blend);
		}
		m_bgcolor = m_mix_scolor(m_bgcolor, pointcolor, m_horizon_blend() * 0.5);
		m_skycolor = m_mix_scolor(m_skycolor, pointcolor, m_horizon_blend() * 0.25);
	}

	float cloud_direct_brightness = 0;
	if(sunlight_seen) {
		if (!m_directional_colored_fog) {
			cloud_direct_brightness = time_brightness;
			if(time_brightness >= 0.2 && time_brightness < 0.7)
				cloud_direct_brightness *= 1.3;
		}
		else {
			cloud_direct_brightness = MYMIN(m_horizon_blend() * 0.15 + m_time_brightness, 1);
		}
	} else {
		cloud_direct_brightness = direct_brightness;
	}
	m_cloud_brightness = m_cloud_brightness * cloud_color_change_fraction +
			cloud_direct_brightness * (1.0 - cloud_color_change_fraction);
	m_cloudcolor_f = video::SColorf(
			m_cloudcolor_bright_f.r * m_cloud_brightness,
			m_cloudcolor_bright_f.g * m_cloud_brightness,
			m_cloudcolor_bright_f.b * m_cloud_brightness,
			1.0);
	if (m_directional_colored_fog) {
		m_cloudcolor_f = m_mix_scolorf(m_cloudcolor_f, video::SColorf(pointcolor), m_horizon_blend() * 0.25);
	}

}