Sophie

Sophie

distrib > Mageia > 3 > i586 > media > core-release-src > by-pkgid > d19dc049c3f21caecf3c79d629b5cc50 > files > 2

vdrift-20120722-6.mga3.src.rpm

--- a/data/skins/simple/menus/AssignControl	Mon Jan 19 23:26:36 1970
+++ b/data/skins/simple/menus/AssignControl	Mon Jan 19 23:26:36 1970
@@ -46,7 +46,7 @@
 image = white.png
 color = 0.172, 0.161, 0.169
 alpha = 0.7
-left = 0.2
-right = 0.2
+left = 0.1
+right = 0.1
 top = 0.48
 height = 0.04
--- a/data/skins/simple/menus/GuiControls	Mon Jan 19 23:26:36 1970
+++ b/data/skins/simple/menus/GuiControls	Mon Jan 19 23:26:36 1970
@@ -82,7 +82,7 @@
 onselect = controledit.string:gui_select:0
 onmoveleft = widget-01d
 onmoveright = widget-01c
-onmoveup = widget-13b
+onmoveup = widget-08b
 onmovedown = widget-02b
 onfocus = widget-01b.sat:0.56
 onblur = widget-01b.sat:0.0
@@ -101,7 +101,7 @@
 onselect = controledit.string:gui_select:1
 onmoveleft = widget-01b
 onmoveright = widget-01d
-onmoveup = widget-13b
+onmoveup = widget-08b
 onmovedown = widget-02c
 onfocus = widget-01c.sat:0.56
 onblur = widget-01c.sat:0.0
@@ -120,7 +120,7 @@
 onselect = controledit.string:gui_select:2
 onmoveleft = widget-01c
 onmoveright = widget-01b
-onmoveup = widget-13b
+onmoveup = widget-08b
 onmovedown = widget-02d
 onfocus = widget-01d.sat:0.56
 onblur = widget-01d.sat:0.0
--- a/data/skins/simple/menus/InGameMain	Mon Jan 19 23:26:36 1970
+++ b/data/skins/simple/menus/InGameMain	Mon Jan 19 23:26:36 1970
@@ -44,10 +44,10 @@
 
 
 [ widget-01 ]
-text = Return to Game
+text = Continue
 fontsize = 0.035
 align = left
-tip = Leave the menu and unpause the game.
+tip = Leave the menu and continue the game.
 onselect = ReturnToGame
 onmoveup = widget-05
 onmovedown = widget-02
@@ -72,7 +72,7 @@
 
 
 [ widget-02 ]
-text = Restart Game
+text = Restart
 fontsize = 0.035
 align = left
 tip = Restart this game using the same car and track settings.
@@ -100,7 +100,7 @@
 
 
 [ widget-03 ]
-text = Leave Game
+text = Abort
 fontsize = 0.035
 align = left
 tip = Leave game and return to the Main menu.
--- a/data/skins/simple/menus/InputDevice	Mon Jan 19 23:26:36 1970
+++ b/data/skins/simple/menus/InputDevice	Mon Jan 19 23:26:36 1970
@@ -82,7 +82,7 @@
 onselect = joystick.type.prev
 onmoveleft = joystick.type.prev
 onmoveright = joystick.type.next
-onmoveup = widget-13b
+onmoveup = widget-11b
 onmovedown = widget-02b
 onfocus = widget-01b.alpha:1 widget-01c.alpha:1 widget-01d.sat:0.56
 onblur = widget-01b.alpha:0 widget-01c.alpha:0 widget-01d.sat:0.0
@@ -102,7 +102,7 @@
 onselect = joystick.type.next
 onmoveleft = joystick.type.prev
 onmoveright = joystick.type.next
-onmoveup = widget-13b
+onmoveup = widget-11b
 onmovedown = widget-02b
 onfocus = widget-01b.alpha:1 widget-01c.alpha:1 widget-01d.sat:0.56
 onblur = widget-01b.alpha:0 widget-01c.alpha:0 widget-01d.sat:0.0
--- a/data/skins/simple/menus/SingleRace	Mon Jan 19 23:26:36 1970
+++ b/data/skins/simple/menus/SingleRace	Mon Jan 19 23:26:36 1970
@@ -860,7 +860,7 @@
 onmoveleft = game.vehicle_damage.prev
 onmoveright = game.vehicle_damage.next
 onmoveup = widget-14b
-onmovedown = widget-16
+onmovedown = widget-16b
 onfocus = widget-15b.alpha:1 widget-15c.alpha:1 widget-15d.sat:0.56
 onblur = widget-15b.alpha:0 widget-15c.alpha:0 widget-15d.sat:0.0
 focus = false
--- a/src/camera.h	Mon Jan 19 23:26:36 1970
+++ b/src/camera.h	Mon Jan 19 23:26:36 1970
@@ -16,7 +16,7 @@
 
 	const std::string & GetName() const { return name; }
 
-	void SetFOV(float value) { fov = std::max(40.0f, std::min(160.0f, value)); }
+	void SetFOV(float value) { fov = std::max(0.0f, std::min(120.0f, value)); }
 
 	float GetFOV() const { return fov; }
 
--- a/src/carcontrolmap_local.cpp	Mon Jan 19 23:26:36 1970
+++ b/src/carcontrolmap_local.cpp	Mon Jan 19 23:26:36 1970
@@ -830,16 +830,6 @@
 	keycodes["y"] = SDLK_y;
 	keycodes["z"] = SDLK_z;
 	keycodes["DELETE"] = SDLK_DELETE;
-	keycodes["KP0"] = SDLK_KP_0;
-	keycodes["KP1"] = SDLK_KP_1;
-	keycodes["KP2"] = SDLK_KP_2;
-	keycodes["KP3"] = SDLK_KP_3;
-	keycodes["KP4"] = SDLK_KP_4;
-	keycodes["KP5"] = SDLK_KP_5;
-	keycodes["KP6"] = SDLK_KP_6;
-	keycodes["KP7"] = SDLK_KP_7;
-	keycodes["KP8"] = SDLK_KP_8;
-	keycodes["KP9"] = SDLK_KP_9;
 	keycodes["KP_PERIOD"] = SDLK_KP_PERIOD;
 	keycodes["KP_DIVIDE"] = SDLK_KP_DIVIDE;
 	keycodes["KP_MULTIPLY"] = SDLK_KP_MULTIPLY;
@@ -872,20 +862,50 @@
 	keycodes["F14"] = SDLK_F14;
 	keycodes["F15"] = SDLK_F15;
 	keycodes["MENU"] = SDLK_MENU;
-	keycodes["APPLICATION"] = SDLK_APPLICATION;
-	keycodes["NUMLOCK"] = SDLK_NUMLOCKCLEAR;
 	keycodes["CAPSLOCK"] = SDLK_CAPSLOCK;
-	keycodes["SCROLLLOCK"] = SDLK_SCROLLLOCK;
 	keycodes["RSHIFT"] = SDLK_RSHIFT;
 	keycodes["LSHIFT"] = SDLK_LSHIFT;
 	keycodes["RCTRL"] = SDLK_RCTRL;
 	keycodes["LCTRL"] = SDLK_LCTRL;
 	keycodes["RALT"] = SDLK_RALT;
 	keycodes["LALT"] = SDLK_LALT;
+#if SDL_VERSION_ATLEAST(2,0,0)
+	keycodes["KP0"] = SDLK_KP_0;
+	keycodes["KP1"] = SDLK_KP_1;
+	keycodes["KP2"] = SDLK_KP_2;
+	keycodes["KP3"] = SDLK_KP_3;
+	keycodes["KP4"] = SDLK_KP_4;
+	keycodes["KP5"] = SDLK_KP_5;
+	keycodes["KP6"] = SDLK_KP_6;
+	keycodes["KP7"] = SDLK_KP_7;
+	keycodes["KP8"] = SDLK_KP_8;
+	keycodes["KP9"] = SDLK_KP_9;
+	keycodes["COMPOSE"] = SDLK_APPLICATION;
+	keycodes["NUMLOCK"] = SDLK_NUMLOCKCLEAR;
+	keycodes["SCROLLLOCK"] = SDLK_SCROLLLOCK;
 	keycodes["RMETA"] = SDLK_RGUI;
 	keycodes["LMETA"] = SDLK_LGUI;
 	keycodes["LSUPER"] = SDLK_LGUI;
 	keycodes["RSUPER"] = SDLK_RGUI;
+#else
+	keycodes["KP0"] = SDLK_KP0;
+	keycodes["KP1"] = SDLK_KP1;
+	keycodes["KP2"] = SDLK_KP2;
+	keycodes["KP3"] = SDLK_KP3;
+	keycodes["KP4"] = SDLK_KP4;
+	keycodes["KP5"] = SDLK_KP5;
+	keycodes["KP6"] = SDLK_KP6;
+	keycodes["KP7"] = SDLK_KP7;
+	keycodes["KP8"] = SDLK_KP8;
+	keycodes["KP9"] = SDLK_KP9;
+	keycodes["COMPOSE"] = SDLK_COMPOSE;
+	keycodes["NUMLOCK"] = SDLK_NUMLOCK;
+	keycodes["SCROLLLOCK"] = SDLK_SCROLLOCK;
+	keycodes["LMETA"] = SDLK_LMETA;
+	keycodes["RMETA"] = SDLK_RMETA;
+	keycodes["LSUPER"] = SDLK_LSUPER;
+	keycodes["RSUPER"] = SDLK_RSUPER;
+#endif
 	return keycodes;
 }
 
--- a/src/game.cpp	Mon Jan 19 23:26:36 1970
+++ b/src/game.cpp	Mon Jan 19 23:26:36 1970
@@ -324,10 +324,6 @@
 
 	info_output << "Shutting down..." << std::endl;
 
-	// Stop the sound thread.
-	if (sound.Enabled())
-		sound.Pause(true);
-
 	LeaveGame();
 
 	// Save settings first incase later deinits cause crashes.
@@ -499,16 +495,7 @@
 	}
 
 	// Connect game actions to gui options
-	set_car_name.connect(gui.GetOption("game.car").signal_val);
-	set_car_paint.connect(gui.GetOption("game.car_paint").signal_val);
-	set_car_color_hue.connect(gui.GetOption("game.car_color_hue").signal_val);
-	set_car_color_sat.connect(gui.GetOption("game.car_color_sat").signal_val);
-	set_car_color_val.connect(gui.GetOption("game.car_color_val").signal_val);
-	set_car_ai_type.connect(gui.GetOption("game.ai_type").signal_val);
-	set_car_ai_level.connect(gui.GetOption("game.ai_level").signal_val);
-	set_cars_num.connect(gui.GetOption("game.cars_num").signal_val);
-	set_track_image.connect(gui.GetOption("game.track").signal_val);
-	set_control.connect(gui.GetOption("controledit.string").signal_val);
+	BindActionsToGUI();
 
 	// Set options from game settings.
 	std::map<std::string, std::string> optionmap;
@@ -531,7 +518,6 @@
 	if (sound.Init(2048, info_output, error_output))
 	{
 		sound.SetVolume(settings.GetSoundVolume());
-		//sound.Pause(false);
 		content.setSound(sound.GetDeviceInfo());
 	}
 	else
@@ -932,22 +918,18 @@
 	if (sound.Enabled())
 	{
 		bool pause_sound = pause || gui.Active();
-		sound.Pause(pause_sound);
-		if (!pause_sound)
-		{
-			PROFILER.beginBlock("sound");
-			MATHVECTOR <float, 3> pos;
-			QUATERNION <float> rot;
-			if (active_camera)
-			{
-				pos = active_camera->GetPosition();
-				rot = active_camera->GetOrientation();
-			}
-			sound.SetListenerPosition(pos[0], pos[1], pos[2]);
-			sound.SetListenerRotation(rot[0], rot[1], rot[2], rot[3]);
-			sound.Update();
-			PROFILER.endBlock("sound");
-		}
+		PROFILER.beginBlock("sound");
+		MATHVECTOR <float, 3> pos;
+		QUATERNION <float> rot;
+		if (active_camera)
+		{
+			pos = active_camera->GetPosition();
+			rot = active_camera->GetOrientation();
+		}
+		sound.SetListenerPosition(pos[0], pos[1], pos[2]);
+		sound.SetListenerRotation(rot[0], rot[1], rot[2], rot[3]);
+		sound.Update(pause_sound);
+		PROFILER.endBlock("sound");
 	}
 
 	//PROFILER.beginBlock("force-feedback");
@@ -1798,9 +1780,12 @@
 	// get car start position marker for camera setup
 	MATHVECTOR<float, 3> car_pos = track.GetStart(0).first;
 
-	// car setup
+	// clear previous car
 	cars.clear();
 
+	// remove previous car sounds
+	sound.Update(true);
+
 	if (LoadCar(
 		cars_name[car_edit_id],
 		cars_paint[car_edit_id],
@@ -1808,14 +1793,13 @@
 		car_pos, track.GetStart(0).second,
 		true, false))
 	{
-		// update car
+		// set car
 		CAR & car = cars.back();
 		dynamics.update(timestep);
 		car.Update(timestep);
 
-		// process car sound sources
-		// should they be loaded for garage car in the first place?
-		sound.Update();
+		// add car sounds
+		sound.Update(true);
 
 		// use car shape center for camera setup
 		car_pos = car.GetPosition();
@@ -1958,7 +1942,7 @@
 	}
 
 	if (numreplays == 0)
-		replaylist.push_back(std::make_pair("", "None"));
+		replaylist.push_back(std::make_pair("none", "None"));
 
 	settings.SetSelectedReplay(replaylist.begin()->first);
 }
@@ -2411,6 +2395,7 @@
 
 	track.Clear();
 	cars.clear();
+	sound.Update(true);
 	hud.SetVisible(false);
 	inputgraph.Hide();
 	trackmap.Unload();
@@ -2419,7 +2404,6 @@
 	pause = false;
 	race_laps = 0;
 	tire_smoke.Clear();
-	sound.Update();
 }
 
 void GAME::StartPractice()
@@ -2473,7 +2457,7 @@
 
 void GAME::StartReplay()
 {
-	if (!settings.GetSelectedReplay().empty() && !NewGame(true))
+	if (settings.GetSelectedReplay() != "none"  && !NewGame(true))
 	{
 		gui.ActivatePage("ReplayStartError", 0.25, error_output);
 	}
@@ -2855,6 +2839,19 @@
 	EditControl();
 }
 
+void GAME::BindActionsToGUI()
+{
+	set_car_name.connect(gui.GetOption("game.car").signal_val);
+	set_car_paint.connect(gui.GetOption("game.car_paint").signal_val);
+	set_car_color_hue.connect(gui.GetOption("game.car_color_hue").signal_val);
+	set_car_color_sat.connect(gui.GetOption("game.car_color_sat").signal_val);
+	set_car_color_val.connect(gui.GetOption("game.car_color_val").signal_val);
+	set_car_ai_type.connect(gui.GetOption("game.ai_type").signal_val);
+	set_car_ai_level.connect(gui.GetOption("game.ai_level").signal_val);
+	set_cars_num.connect(gui.GetOption("game.cars_num").signal_val);
+	set_track_image.connect(gui.GetOption("game.track").signal_val);
+	set_control.connect(gui.GetOption("controledit.string").signal_val);
+}
 
 void GAME::RegisterActions()
 {
--- a/src/game.h	Mon Jan 19 23:26:36 1970
+++ b/src/game.h	Mon Jan 19 23:26:36 1970
@@ -201,6 +201,7 @@
 	void SetTrackImage(const std::string & value);
 	void SetControl(const std::string & value);
 
+	void BindActionsToGUI();
 	void RegisterActions();
 	void InitActionMap(std::map<std::string, Slot0*> & actionmap);
 
--- a/src/sound.cpp	Mon Jan 19 23:26:36 1970
+++ b/src/sound.cpp	Mon Jan 19 23:26:36 1970
@@ -30,17 +30,20 @@
 }
 
 SOUND::SOUND() :
+	log_error(0),
 	deviceinfo(0, 0, 0, 0),
+	sound_volume(0),
 	initdone(false),
 	disable(false),
-	paused(true),
 	sampler_lock(0),
 	source_lock(0),
+	set_pause(true),
 	max_active_sources(64),
 	sources_num(0),
-	samplers_num(0)
+	sources_pause(true),
+	samplers_num(0),
+	samplers_pause(true)
 {
-	volume_filter.SetFilterOrder0(1.0);
 	sources.reserve(64);
 	samplers.reserve(64);
 }
@@ -115,11 +118,13 @@
 	}
 
 	deviceinfo = SOUNDINFO(samples, frequency, channels, bytespersample);
-
+	log_error = &error_output;
 	initdone = true;
-
 	SetVolume(1.0);
 
+	// enable sound, run callback
+	SDL_PauseAudio(false);
+
 	return true;
 }
 
@@ -138,46 +143,21 @@
 	disable = true;
 }
 
-void SOUND::Pause(bool value)
-{
-	if (paused != value)
-	{
-		SDL_PauseAudio(value);
-		paused = value;
-	}
-}
-
-void SOUND::Update()
+void SOUND::Update(bool pause)
 {
 	if (disable) return;
 
+	set_pause = pause;
+
 	GetSourceChanges();
 
 	ProcessSourceStop();
 
-	ProcessSourceRemove();
-
 	ProcessSources();
 
-	SetSamplerChanges();
-
-	// short circuit if paused(sound thread blocked)
-	if (paused)
-	{
-		GetSamplerChanges();
-
-		ProcessSamplerAdd();
-
-		ProcessSamplerRemove();
-
-		SetSourceChanges();
-
-		GetSourceChanges();
-
-		ProcessSourceStop();
+	ProcessSourceRemove();
 
-		ProcessSourceRemove();
-	}
+	SetSamplerChanges();
 }
 
 void SOUND::SetMaxActiveSources(size_t value)
@@ -192,18 +172,24 @@
 	size_t id = item_num;
 	if (id < items.size())
 	{
+		// reuse free slot
 		size_t idn = items[id].id;
 		if (idn != id)
 		{
-			// swap back redirected item
+			// free slot is redirecting to other item
 			assert(idn < id);
+
+			// swap redirected item back
 			items[id] = items[idn];
+
+			// use now free slot
 			id = idn;
 		}
 		items[id] = item;
 	}
 	else
 	{
+		// add item to new slot
 		items.push_back(item);
 	}
 	items[id].id = id;
@@ -217,9 +203,14 @@
 inline void RemoveItem(size_t id, std::vector<T> & items, size_t & item_num)
 {
 	assert(id < items.size());
+
+	// get item true id
 	size_t idn = items[id].id;
 	assert(idn < item_num);
+
+	// pop last item
 	--item_num;
+
 	// swap last item with current
 	size_t idl = items[item_num].id;
 	if (idl != item_num)
@@ -270,14 +261,13 @@
 	ns.id = -1;
 	sampler_add.getFirst().push_back(ns);
 
-	//std::cout << "Add sound source: " << id << " " << buffer->GetName() << std::endl;
+	//*log_error << "Add sound source: " << id << " " << buffer->GetName() << std::endl;
 	return id;
 }
 
 void SOUND::RemoveSource(size_t id)
 {
-	// notify sound thread, it will notify main thread to remove the source
-	//std::cout << "To be removed source: " << id << " " << sources[sources[id].id].buffer->GetName() << std::endl;
+	// notify sound and main thread to remove the source/sampler
 	sampler_remove.getFirst().push_back(id);
 }
 
@@ -343,14 +333,13 @@
 
 void SOUND::SetVolume(float value)
 {
-	volume_filter.SetFilterOrder0(clamp(value, 0.f, 1.f));
+	sound_volume = value;
 }
 
 void SOUND::GetSourceChanges()
 {
 	Lock(source_lock);
 	source_stop.swapFirst();
-	source_remove.swapFirst();
 	Unlock(source_lock);
 }
 
@@ -368,17 +357,18 @@
 
 void SOUND::ProcessSourceRemove()
 {
-	std::vector<size_t> & sremove = source_remove.getFirst();
+	std::vector<size_t> & sremove = sampler_remove.getFirst();
 	for (size_t i = 0; i < sremove.size(); ++i)
 	{
 		size_t id = sremove[i];
 		assert(id < sources.size());
+
 		size_t idn = sources[id].id;
 		assert(idn < sources_num);
-		//std::cout << "Remove sound source: " << id << " " << sources[idn].buffer->GetName() << std::endl;
+		//*log_error << "Remove sound source: " << id << " " << sources[idn].buffer->GetName() << std::endl;
+
 		RemoveItem(id, sources, sources_num);
 	}
-	sremove.clear();
 }
 
 void SOUND::ProcessSources()
@@ -436,8 +426,11 @@
 			}
 		}
 
-		supdate[i].gain1 = gain1 * Sampler::denom;
-		supdate[i].gain2 = gain2 * Sampler::denom;
+		// fade sound volume
+		float volume = set_pause ? 0 : sound_volume;
+
+		supdate[i].gain1 = volume * gain1 * Sampler::denom;
+		supdate[i].gain2 = volume * gain2 * Sampler::denom;
 		supdate[i].pitch = src.pitch * Sampler::denom;
 	}
 
@@ -471,6 +464,7 @@
 	if (sampler_update.getFirst().size()) sampler_update.swapFirst();
 	if (sampler_add.getFirst().size()) sampler_add.swapFirst();
 	if (sampler_remove.getFirst().size()) sampler_remove.swapFirst();
+	sources_pause = set_pause;
 	Unlock(sampler_lock);
 }
 
@@ -478,33 +472,41 @@
 {
 	Lock(sampler_lock);
 	sampler_update.swapLast();
-	sampler_remove.swapLast();
 	sampler_add.swapLast();
+	sampler_remove.swapLast();
+	samplers_fade = samplers_pause != sources_pause;
+	samplers_pause = sources_pause;
 	Unlock(sampler_lock);
 }
 
 void SOUND::ProcessSamplerUpdate()
 {
 	std::vector<SamplerUpdate> & supdate = sampler_update.getLast();
-	if (samplers_num == supdate.size())
+	if (supdate.empty()) return;
+	
+	assert(samplers_num == supdate.size());
+	for (size_t i = 0; i < samplers_num; ++i)
 	{
-		for (size_t i = 0; i < samplers_num; ++i)
-		{
-			samplers[i].gain1 = supdate[i].gain1;
-			samplers[i].gain2 = supdate[i].gain2;
-			samplers[i].pitch = supdate[i].pitch;
-		}
+		samplers[i].gain1 = supdate[i].gain1;
+		samplers[i].gain2 = supdate[i].gain2;
+		samplers[i].pitch = supdate[i].pitch;
 	}
 	supdate.clear();
 }
 
 void SOUND::ProcessSamplers(unsigned char *stream, int len)
 {
-	// set buffers and clear stream
+	// clear stream
+	memset(stream, 0, len);
+
+	// pause sampling
+	if (samplers_pause && !samplers_fade)
+		return;
+
+	// init sampling buffers
 	int len4 = len / 4;
 	buffer1.resize(len4);
 	buffer2.resize(len4);
-	memset(stream, 0, len);
 
 	// run samplers
 	short * sstream = (short*)stream;
@@ -519,13 +521,17 @@
 		{
 			SampleAndAdvanceWithPitch16bit(smp, &buffer1[0], &buffer2[0], len4);
 
-			volume_filter.Filter(&buffer1[0], &buffer2[0], len4);
-
 			for (int n = 0; n < len4; ++n)
 			{
 				int pos = n * 2;
-				sstream[pos] = clamp(sstream[pos] + buffer1[n], -32768, 32767);
-				sstream[pos + 1] = clamp(sstream[pos + 1] + buffer2[n], -32768, 32767);
+				int val1 = sstream[pos] + buffer1[n];
+				int val2 = sstream[pos + 1] + buffer2[n];
+
+				val1 = clamp(val1, -32768, 32767);
+				val2 = clamp(val2, -32768, 32767);
+
+				sstream[pos] = val1;
+				sstream[pos + 1] = val2;
 			}
 		}
 		else
@@ -541,17 +547,13 @@
 void SOUND::ProcessSamplerRemove()
 {
 	std::vector<size_t> & sremove = sampler_remove.getLast();
-	if (!sremove.empty())
+	for (size_t i = 0; i < sremove.size(); ++i)
 	{
-		for (size_t i = 0; i < sremove.size(); ++i)
-		{
-			size_t id = sremove[i];
-			assert(id < samplers.size());
-			RemoveItem(id, samplers, samplers_num);
-		}
-		source_remove.getLast() = sremove;
-		sremove.clear();
+		size_t id = sremove[i];
+		assert(id < samplers.size());
+		RemoveItem(id, samplers, samplers_num);
 	}
+	sremove.clear();
 }
 
 void SOUND::ProcessSamplerAdd()
@@ -589,7 +591,6 @@
 {
 	Lock(source_lock);
 	if (source_stop.getLast().size()) source_stop.swapLast();
-	if (source_remove.getLast().size()) source_remove.swapLast();
 	Unlock(source_lock);
 }
 
@@ -600,12 +601,12 @@
 
 	GetSamplerChanges();
 
+	ProcessSamplerAdd();
+
 	ProcessSamplerUpdate();
 
 	ProcessSamplers(stream, len);
 
-	ProcessSamplerAdd();
-
 	ProcessSamplerRemove();
 
 	SetSourceChanges();
@@ -622,9 +623,10 @@
 	assert(len > 0);
 	assert(sampler.buffer);
 
-	// if not playing, fill output buffers with silence, should not happen
+	// if not playing, fill output buffers with silence
 	if (!sampler.playing)
 	{
+		// should be dealt with before getting here
 		assert(0);
 		for (int i = 0; i < len; ++i)
 		{
--- a/src/sound.h	Mon Jan 19 23:26:36 1970
+++ b/src/sound.h	Mon Jan 19 23:26:36 1970
@@ -33,11 +33,8 @@
 	// disable sound
 	void Disable();
 
-	// pause sound
-	void Pause(bool value);
-
 	// commit state changes
-	void Update();
+	void Update(bool pause);
 
 	// active sources limit can be adjusted at runtime
 	void SetMaxActiveSources(size_t value);
@@ -69,14 +66,14 @@
 	void SetVolume(float value);
 
 private:
+	std::ostream * log_error;
 	SOUNDINFO deviceinfo;
-	SOUNDFILTER volume_filter;
 	MATHVECTOR<float, 3> listener_pos;
 	MATHVECTOR<float, 3> listener_vel;
 	QUATERNION<float> listener_rot;
+	float sound_volume;
 	bool initdone;
 	bool disable;
-	bool paused;
 
 	// state structs
 	struct Source
@@ -95,8 +92,8 @@
 
 	struct Sampler
 	{
-		static const int denom = 1 << 15;
-		static const int max_gain_delta = (denom * 100) / 44100;
+		static const int denom = 32768;
+		static const int max_gain_delta = (denom * 173) / 44100; // 256 samples from min to max gain
 		const SOUNDBUFFER * buffer;
 		int samples_per_channel;
 		int sample_pos;
@@ -135,21 +132,24 @@
 	TrippleBuffer<SamplerUpdate> sampler_update;
 	TrippleBuffer<SamplerAdd> sampler_add;
 	TrippleBuffer<size_t> sampler_remove;
-	TrippleBuffer<size_t> source_remove;
 	TrippleBuffer<size_t> source_stop;
 	SDL_mutex * sampler_lock;
 	SDL_mutex * source_lock;
+	bool set_pause;
 
 	// sound sources state
 	std::vector<SourceActive> sources_active;
 	std::vector<Source> sources;
 	size_t max_active_sources;
 	size_t sources_num;
+	bool sources_pause;
 
 	// sound thread state
 	std::vector<int> buffer1, buffer2;
 	std::vector<Sampler> samplers;
 	size_t samplers_num;
+	bool samplers_pause;
+	bool samplers_fade;
 
 	// main thread methods
 	void GetSourceChanges();
--- a/src/texture.cpp	Mon Jan 19 23:26:36 1970
+++ b/src/texture.cpp	Mon Jan 19 23:26:36 1970
@@ -179,6 +179,7 @@
 	else
 	{
 		error << "Error loading texture file: " + path << std::endl;
+		error << IMG_GetError();
 		return false;
 	}
 
@@ -303,6 +304,7 @@
 		else
 		{
 			error << "Error loading texture file: " + path + " (" + cubefiles[i] + ")" << std::endl;
+			error << IMG_GetError();
 			return false;
 		}
 
@@ -477,6 +479,7 @@
 		if (!orig_surface)
 		{
 			error << "Error loading texture file: " << path << std::endl;
+			error << IMG_GetError();
 			return false;
 		}
 	}
--- a/src/cardynamics.cpp	Mon Jan 19 23:26:36 1970
+++ b/src/cardynamics.cpp	Mon Jan 19 23:26:36 1970
@@ -1791,23 +1791,29 @@
 
 bool CARDYNAMICS::WheelContactCallback(
 	btManifoldPoint& cp,
-	const btCollisionObject* colObj0,
-	int partId0,
+	const btCollisionObjectWrapper* col0,
+	int part0,
 	int index0,
-	const btCollisionObject* colObj1,
-	int partId1,
+	const btCollisionObjectWrapper* col1,
+	int part1,
 	int index1)
 {
-	// cars are fracture bodies, wheel is a cylinder shape
-	const btCollisionShape* shape = colObj0->getCollisionShape();
-	if ((colObj0->getInternalType() & CO_FRACTURE_TYPE) &&
+#if (BT_BULLET_VERSION < 281)
+	const btCollisionObject* obj = col0;
+	const btCollisionShape* shape = obj->getCollisionShape();
+	const btCollisionShape* rootshape = obj->getRootCollisionShape();
+#else
+	const btCollisionObject* obj = col0->getCollisionObject();
+	const btCollisionShape* shape = col0->getCollisionShape();
+	const btCollisionShape* rootshape = obj->getCollisionShape();
+#endif
+	if ((obj->getInternalType() & CO_FRACTURE_TYPE) &&
 		(shape->getShapeType() == CYLINDER_SHAPE_PROXYTYPE))
 	{
-		// is contact within contact patch?
-		const btCompoundShape* car = static_cast<const btCompoundShape*>(colObj0->getRootCollisionShape());
-		const btCylinderShapeX* wheel = static_cast<const btCylinderShapeX*>(shape);
-		btVector3 contactPoint = cp.m_localPointA - car->getChildTransform(cp.m_index0).getOrigin();
-		if (-direction::up.dot(contactPoint) > 0.5 * wheel->getRadius())
+		const btCompoundShape* carshape = static_cast<const btCompoundShape*>(rootshape);
+		const btCylinderShapeX* wheelshape = static_cast<const btCylinderShapeX*>(shape);
+		btVector3 contactPoint = cp.m_localPointA - carshape->getChildTransform(cp.m_index0).getOrigin();
+		if (-direction::up.dot(contactPoint) > 0.5 * wheelshape->getRadius())
 		{
 			// break contact (hack)
 			cp.m_normalWorldOnB = btVector3(0, 0, 0);
--- a/src/cardynamics.h	Mon Jan 19 23:26:36 1970
+++ b/src/cardynamics.h	Mon Jan 19 23:26:36 1970
@@ -25,6 +25,12 @@
 class FractureBody;
 class PTree;
 
+#if (BT_BULLET_VERSION < 281)
+#define btCollisionObjectWrapper btCollisionObject
+#else
+struct btCollisionObjectWrapper;
+#endif
+
 class CARDYNAMICS : public btActionInterface
 {
 friend class PERFORMANCE_TESTING;
@@ -151,11 +157,11 @@
 
 	static bool WheelContactCallback(
 		btManifoldPoint& cp,
-		const btCollisionObject* colObj0,
-		int partId0,
+		const btCollisionObjectWrapper* col0,
+		int part0,
 		int index0,
-		const btCollisionObject* colObj1,
-		int partId1,
+		const btCollisionObjectWrapper* col1,
+		int part1,
 		int index1);
 
 protected:
--- a/src/dynamicsworld.cpp	Mon Jan 19 23:26:36 1970
+++ b/src/dynamicsworld.cpp	Mon Jan 19 23:26:36 1970
@@ -105,7 +105,7 @@
 	int patch_id = -1;
 	const BEZIER * b = 0;
 	const TRACKSURFACE * s = TRACKSURFACE::None();
-	btCollisionObject * c = 0;
+	const btCollisionObject * c = 0;
 
 	MyRayResultCallback ray(origin, p, caster);
 	rayTest(origin, p, ray);
@@ -221,6 +221,7 @@
 
 void DynamicsWorld::fractureCallback()
 {
+#if (BT_BULLET_VERSION < 281)
 	m_activeConnections.resize(0);
 
 	int numManifolds = getDispatcher()->getNumManifolds();
@@ -268,4 +269,5 @@
 		btRigidBody* child = body->updateConnection(con_id);
 		if (child) addRigidBody(child);
 	}
+#endif
 }