(svn r12743) [NewGRF_ports] -Sync: with trunk r12705:12741.
--- a/configure Wed Apr 16 22:16:04 2008 +0000
+++ b/configure Wed Apr 16 22:34:14 2008 +0000
@@ -96,7 +96,7 @@
if ($0 == "MSVC" && "'$os'" != "MSVC") { next; }
if ($0 == "DIRECTMUSIC" && "'$with_direct_music'" == "0") { next; }
if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" ) { next; }
- if ($0 == "NO_THREADS" && "'$with_threads'" == "0") { next; }
+ if ($0 == "HAVE_THREAD" && "'$with_threads'" == "0") { next; }
skip += 1;
--- a/projects/generate Wed Apr 16 22:16:04 2008 +0000
+++ b/projects/generate Wed Apr 16 22:34:14 2008 +0000
@@ -83,7 +83,7 @@
if ($0 == "MSVC" && "'$os'" != "MSVC") { next; }
if ($0 == "DIRECTMUSIC" && "'$enable_directmusic'" != "1") { next; }
if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" ) { next; }
- if ($0 == "NO_THREADS" && "'$with_threads'" == "0") { next; }
+ if ($0 == "HAVE_THREAD" && "'$with_threads'" == "0") { next; }
skip += 1;
--- a/projects/generate.vbs Wed Apr 16 22:16:04 2008 +0000
+++ b/projects/generate.vbs Wed Apr 16 22:34:14 2008 +0000
@@ -72,7 +72,7 @@
line = "WIN32" Or _
line = "MSVC" Or _
line = "DIRECTMUSIC" Or _
- line = "NO_THREADS" _
+ line = "HAVE_THREAD" _
) Then skip = skip + 1
deep = deep + 1
Case "#"
--- a/projects/openttd_vs80.vcproj Wed Apr 16 22:16:04 2008 +0000
+++ b/projects/openttd_vs80.vcproj Wed Apr 16 22:34:14 2008 +0000
@@ -744,7 +744,11 @@
>
</File>
<File
- RelativePath=".\..\src\thread.cpp"
+ RelativePath=".\..\src\thread_win32.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\fiber_win32.cpp"
>
</File>
<File
@@ -796,6 +800,10 @@
>
</File>
<File
+ RelativePath=".\..\src\core\alloc_type.hpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\articulated_vehicles.h"
>
</File>
@@ -948,6 +956,10 @@
>
</File>
<File
+ RelativePath=".\..\src\fiber.hpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\fileio.h"
>
</File>
@@ -2252,6 +2264,10 @@
>
</File>
<File
+ RelativePath=".\..\src\misc\countedobj.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\misc\countedptr.hpp"
>
</File>
@@ -2276,6 +2292,10 @@
>
</File>
<File
+ RelativePath=".\..\src\misc\smallveh.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\misc\str.hpp"
>
</File>
--- a/projects/openttd_vs90.vcproj Wed Apr 16 22:16:04 2008 +0000
+++ b/projects/openttd_vs90.vcproj Wed Apr 16 22:34:14 2008 +0000
@@ -733,7 +733,11 @@
>
</File>
<File
- RelativePath=".\..\src\thread.cpp"
+ RelativePath=".\..\src\thread_win32.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\fiber_win32.cpp"
>
</File>
<File
@@ -789,6 +793,10 @@
>
</File>
<File
+ RelativePath=".\..\src\core\alloc_type.hpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\articulated_vehicles.h"
>
</File>
@@ -941,6 +949,10 @@
>
</File>
<File
+ RelativePath=".\..\src\fiber.hpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\fileio.h"
>
</File>
@@ -2229,6 +2241,10 @@
>
</File>
<File
+ RelativePath=".\..\src\misc\countedobj.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\misc\countedptr.hpp"
>
</File>
@@ -2253,6 +2269,10 @@
>
</File>
<File
+ RelativePath=".\..\src\misc\smallveh.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\misc\str.hpp"
>
</File>
--- a/source.list Wed Apr 16 22:16:04 2008 +0000
+++ b/source.list Wed Apr 16 22:34:14 2008 +0000
@@ -79,7 +79,21 @@
strings.cpp
texteff.cpp
tgp.cpp
-thread.cpp
+#if HAVE_THREAD
+ #if WIN32
+ thread_win32.cpp
+ fiber_win32.cpp
+ #else
+ #if OS2
+ thread_os2.cpp
+ #else
+ thread_pthread.cpp
+ #end
+ fiber_thread.cpp
+ #end
+#else
+ thread_none.cpp
+#end
tile_map.cpp
#if WIN32
#else
@@ -146,6 +160,7 @@
engine_func.h
engine_type.h
core/enum_type.hpp
+fiber.hpp
fileio.h
fios.h
fontcache.h
@@ -498,12 +513,14 @@
misc/autoptr.hpp
misc/binaryheap.hpp
misc/blob.hpp
+misc/countedobj.cpp
misc/countedptr.hpp
misc/crc32.hpp
misc/dbg_helpers.cpp
misc/dbg_helpers.h
misc/fixedsizearray.hpp
misc/hashtable.hpp
+misc/smallveh.h
misc/str.hpp
misc/strapi.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fiber.hpp Wed Apr 16 22:34:14 2008 +0000
@@ -0,0 +1,53 @@
+/* $Id$ */
+
+/** @file fiber.hpp */
+
+#ifndef FIBER_HPP
+#define FIBER_HPP
+
+typedef void (CDECL *FiberFunc)(void *);
+
+class Fiber {
+public:
+ /**
+ * Switch to this fiber.
+ */
+ virtual void SwitchToFiber() = 0;
+
+ /**
+ * Exit a fiber.
+ */
+ virtual void Exit() = 0;
+
+ /**
+ * Check if a fiber is running.
+ */
+ virtual bool IsRunning() = 0;
+
+ /**
+ * Get the 'param' data of the Fiber.
+ */
+ virtual void *GetFiberData() = 0;
+
+ /**
+ * Virtual Destructor to mute warnings.
+ */
+ virtual ~Fiber() {};
+
+ /**
+ * Create a new fiber, calling proc(param) when running.
+ */
+ static Fiber *New(FiberFunc proc, void *param);
+
+ /**
+ * Attach a current thread to a new fiber.
+ */
+ static Fiber *AttachCurrent(void *param);
+
+ /**
+ * Get the 'param' data of the current active Fiber.
+ */
+ static void *GetCurrentFiberData();
+};
+
+#endif /* FIBER_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fiber_thread.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -0,0 +1,153 @@
+/* $Id$ */
+
+/** @file fiber_thread.cpp ThreadObject implementation of Fiber. */
+
+#include "stdafx.h"
+#include "fiber.hpp"
+#include "thread.h"
+#include <stdlib.h>
+
+class Fiber_Thread : public Fiber {
+private:
+ ThreadObject *m_thread;
+ FiberFunc m_proc;
+ void *m_param;
+ bool m_attached;
+ ThreadSemaphore *m_sem;
+ bool m_kill;
+
+ static Fiber_Thread *s_current;
+ static Fiber_Thread *s_main;
+
+public:
+ /**
+ * Create a ThreadObject fiber and start it, calling proc(param).
+ */
+ Fiber_Thread(FiberFunc proc, void *param) :
+ m_thread(NULL),
+ m_proc(proc),
+ m_param(param),
+ m_attached(false),
+ m_kill(false)
+ {
+ this->m_sem = ThreadSemaphore::New();
+ /* Create a thread and start stFiberProc */
+ this->m_thread = ThreadObject::New(&stFiberProc, this);
+ }
+
+ /**
+ * Create a ThreadObject fiber and attach current thread to it.
+ */
+ Fiber_Thread(void *param) :
+ m_thread(NULL),
+ m_proc(NULL),
+ m_param(param),
+ m_attached(true),
+ m_kill(false)
+ {
+ this->m_sem = ThreadSemaphore::New();
+ /* Attach the current thread to this Fiber */
+ this->m_thread = ThreadObject::AttachCurrent();
+ /* We are the current thread */
+ if (s_current == NULL) s_current = this;
+ if (s_main == NULL) s_main = this;
+ }
+
+ ~Fiber_Thread()
+ {
+ /* Remove the thread if needed */
+ if (this->m_thread != NULL) {
+ assert(this->m_attached || !this->m_thread->IsRunning());
+ delete this->m_thread;
+ }
+ /* Remove the semaphore */
+ delete this->m_sem;
+ }
+
+ /* virtual */ void SwitchToFiber()
+ {
+ /* You can't switch to yourself */
+ assert(s_current != this);
+ Fiber_Thread *cur = s_current;
+
+ /* Continue the execution of 'this' Fiber */
+ this->m_sem->Set();
+ /* Hold the execution of the current Fiber */
+ cur->m_sem->Wait();
+ if (this->m_kill) {
+ /* If the thread we switched too was killed, join it so it can finish quiting */
+ this->m_thread->Join();
+ }
+ /* If we continue, we are the current thread */
+ s_current = cur;
+ }
+
+ /* virtual */ void Exit()
+ {
+ /* Kill off our thread */
+ this->m_kill = true;
+ this->m_thread->Exit();
+ }
+
+ /* virtual */ bool IsRunning()
+ {
+ if (this->m_thread == NULL) return false;
+ return this->m_thread->IsRunning();
+ }
+
+ /* virtual */ void *GetFiberData()
+ {
+ return this->m_param;
+ }
+
+ static Fiber_Thread *GetCurrentFiber()
+ {
+ return s_current;
+ }
+
+private:
+ /**
+ * First function which is called within the fiber.
+ */
+ static void * CDECL stFiberProc(void *fiber)
+ {
+ Fiber_Thread *cur = (Fiber_Thread *)fiber;
+ /* Now suspend the thread until we get SwitchToFiber() for the first time */
+ cur->m_sem->Wait();
+ /* If we continue, we are the current thread */
+ s_current = cur;
+
+ try {
+ cur->m_proc(cur->m_param);
+ } catch (...) {
+ /* Unlock the main thread */
+ s_main->m_sem->Set();
+ throw;
+ }
+
+ return NULL;
+ }
+};
+
+/* Initialize the static member of Fiber_Thread */
+/* static */ Fiber_Thread *Fiber_Thread::s_current = NULL;
+/* static */ Fiber_Thread *Fiber_Thread::s_main = NULL;
+
+#ifndef WIN32
+
+/* static */ Fiber *Fiber::New(FiberFunc proc, void *param)
+{
+ return new Fiber_Thread(proc, param);
+}
+
+/* static */ Fiber *Fiber::AttachCurrent(void *param)
+{
+ return new Fiber_Thread(param);
+}
+
+/* static */ void *Fiber::GetCurrentFiberData()
+{
+ return Fiber_Thread::GetCurrentFiber()->GetFiberData();
+}
+
+#endif /* WIN32 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fiber_win32.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -0,0 +1,206 @@
+/* $Id$ */
+
+/** @file fiber_win32.cpp Win32 implementation of Fiber. */
+
+#include "stdafx.h"
+#include "fiber.hpp"
+#include <stdlib.h>
+#include <windows.h>
+#include <process.h>
+
+class Fiber_Win32 : public Fiber {
+private:
+ LPVOID m_fiber;
+ FiberFunc m_proc;
+ void *m_param;
+ bool m_attached;
+
+ static Fiber_Win32 *s_main;
+
+public:
+ /**
+ * Create a win32 fiber and start it, calling proc(param).
+ */
+ Fiber_Win32(FiberFunc proc, void *param) :
+ m_fiber(NULL),
+ m_proc(proc),
+ m_param(param),
+ m_attached(false)
+ {
+ CreateFiber();
+ }
+
+ /**
+ * Create a win32 fiber and attach current thread to it.
+ */
+ Fiber_Win32(void *param) :
+ m_fiber(NULL),
+ m_proc(NULL),
+ m_param(param),
+ m_attached(true)
+ {
+ ConvertThreadToFiber();
+ if (s_main == NULL) s_main = this;
+ }
+
+ /* virtual */ ~Fiber_Win32()
+ {
+ if (this->m_fiber != NULL) {
+ if (this->m_attached) {
+ this->ConvertFiberToThread();
+ } else {
+ this->DeleteFiber();
+ }
+ }
+ }
+
+ /* virtual */ void SwitchToFiber()
+ {
+ typedef VOID (WINAPI *FnSwitchToFiber)(LPVOID fiber);
+
+ static FnSwitchToFiber fnSwitchToFiber = (FnSwitchToFiber)stGetProcAddr("SwitchToFiber");
+ assert(fnSwitchToFiber != NULL);
+
+ fnSwitchToFiber(this->m_fiber);
+ }
+
+ /* virtual */ void Exit()
+ {
+ /* Simply switch back to the main fiber, we kill the fiber sooner or later */
+ s_main->SwitchToFiber();
+ }
+
+ /* virtual */ bool IsRunning()
+ {
+ return this->m_fiber != NULL;
+ }
+
+ /* virtual */ void *GetFiberData()
+ {
+ return this->m_param;
+ }
+
+ /**
+ * Win95 doesn't have Fiber support. So check if we have Fiber support,
+ * and else fall back on Fiber_Thread.
+ */
+ static bool IsSupported()
+ {
+ static bool first_run = true;
+ static bool is_supported = false;
+
+ if (first_run) {
+ first_run = false;
+ static const char *names[] = {
+ "ConvertThreadToFiber",
+ "CreateFiber",
+ "DeleteFiber",
+ "ConvertFiberToThread",
+ "SwitchToFiber"};
+ for (size_t i = 0; i < lengthof(names); i++) {
+ if (stGetProcAddr(names[i]) == NULL) return false;
+ }
+ is_supported = true;
+ }
+ return is_supported;
+ }
+
+private:
+ /**
+ * Get a function from kernel32.dll.
+ * @param name Function to get.
+ * @return Proc to the function, or NULL when not found.
+ */
+ static FARPROC stGetProcAddr(const char *name)
+ {
+ static HMODULE hKernel = LoadLibraryA("kernel32.dll");
+ return GetProcAddress(hKernel, name);
+ }
+
+ /**
+ * First function which is called within the fiber.
+ */
+ static VOID CALLBACK stFiberProc(LPVOID fiber)
+ {
+ Fiber_Win32 *cur = (Fiber_Win32 *)fiber;
+ cur->m_proc(cur->m_param);
+ }
+
+ /**
+ * Delete a fiber.
+ */
+ void DeleteFiber()
+ {
+ typedef VOID (WINAPI *FnDeleteFiber)(LPVOID lpFiber);
+
+ static FnDeleteFiber fnDeleteFiber = (FnDeleteFiber)stGetProcAddr("DeleteFiber");
+ assert(fnDeleteFiber != NULL);
+
+ fnDeleteFiber(this->m_fiber);
+ this->m_fiber = NULL;
+ }
+
+ /**
+ * Convert a current thread to a fiber.
+ */
+ void ConvertThreadToFiber()
+ {
+ typedef LPVOID (WINAPI *FnConvertThreadToFiber)(LPVOID lpParameter);
+
+ static FnConvertThreadToFiber fnConvertThreadToFiber = (FnConvertThreadToFiber)stGetProcAddr("ConvertThreadToFiber");
+ assert(fnConvertThreadToFiber != NULL);
+
+ this->m_fiber = fnConvertThreadToFiber(this);
+ }
+
+ /**
+ * Create a new fiber.
+ */
+ void CreateFiber()
+ {
+ typedef LPVOID (WINAPI *FnCreateFiber)(SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter);
+
+ static FnCreateFiber fnCreateFiber = (FnCreateFiber)stGetProcAddr("CreateFiber");
+ assert(fnCreateFiber != NULL);
+
+ this->m_fiber = fnCreateFiber(0, &stFiberProc, this);
+ }
+
+ /**
+ * Convert a fiber back to a thread.
+ */
+ void ConvertFiberToThread()
+ {
+ typedef BOOL (WINAPI *FnConvertFiberToThread)();
+
+ static FnConvertFiberToThread fnConvertFiberToThread = (FnConvertFiberToThread)stGetProcAddr("ConvertFiberToThread");
+ assert(fnConvertFiberToThread != NULL);
+
+ fnConvertFiberToThread();
+ this->m_fiber = NULL;
+ }
+};
+
+/* Initialize the static member of Fiber_Win32 */
+/* static */ Fiber_Win32 *Fiber_Win32::s_main = NULL;
+
+/* Include Fiber_Thread, as Win95 needs it */
+#include "fiber_thread.cpp"
+
+/* static */ Fiber *Fiber::New(FiberFunc proc, void *param)
+{
+ if (Fiber_Win32::IsSupported()) return new Fiber_Win32(proc, param);
+ return new Fiber_Thread(proc, param);
+}
+
+/* static */ Fiber *Fiber::AttachCurrent(void *param)
+{
+ if (Fiber_Win32::IsSupported()) return new Fiber_Win32(param);
+ return new Fiber_Thread(param);
+}
+
+/* static */ void *Fiber::GetCurrentFiberData()
+{
+ if (Fiber_Win32::IsSupported()) return ((Fiber *)::GetFiberData())->GetFiberData();
+ return Fiber_Thread::GetCurrentFiber()->GetFiberData();
+}
--- a/src/genworld.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/genworld.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -84,7 +84,7 @@
/**
* The internal, real, generate function.
*/
-static void *_GenerateWorld(void *arg)
+static void * CDECL _GenerateWorld(void *arg)
{
_generating_world = true;
if (_network_dedicated) DEBUG(net, 0, "Generating map, please wait...");
@@ -194,7 +194,7 @@
{
if (_gw.thread == NULL) return;
_gw.quit_thread = true;
- OTTDJoinThread((OTTDThread*)_gw.thread);
+ _gw.thread->Join();
_gw.thread = NULL;
_gw.threaded = false;
}
@@ -228,6 +228,8 @@
if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
/* Show all vital windows again, because we have hidden them */
if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows();
+
+ ThreadObject *thread = _gw.thread;
_gw.active = false;
_gw.thread = NULL;
_gw.proc = NULL;
@@ -237,7 +239,7 @@
DeleteWindowById(WC_GENERATE_PROGRESS_WINDOW, 0);
MarkWholeScreenDirty();
- OTTDExitThread();
+ thread->Exit();
}
/**
@@ -282,7 +284,7 @@
SetupColorsAndInitialWindow();
if (_network_dedicated ||
- (_gw.thread = OTTDCreateThread(&_GenerateWorld, NULL)) == NULL) {
+ (_gw.thread = ThreadObject::New(&_GenerateWorld, NULL)) == NULL) {
DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode");
_gw.threaded = false;
_GenerateWorld(NULL);
--- a/src/genworld.h Wed Apr 16 22:16:04 2008 +0000
+++ b/src/genworld.h Wed Apr 16 22:34:14 2008 +0000
@@ -5,16 +5,6 @@
#ifndef GENWORLD_H
#define GENWORLD_H
-/* If OTTDThread isn't defined, define it to a void, but make sure to undefine
- * it after this include. This makes including genworld.h easier, as you
- * don't need to include thread.h before it, while it stays possible to
- * include it after it, and still work.
- */
-#ifndef OTTDThread
-#define TEMPORARY_OTTDTHREAD_DEFINITION
-#define OTTDThread void
-#endif
-
#include "player_type.h"
/*
@@ -43,14 +33,9 @@
uint size_y; ///< Y-size of the map
gw_done_proc *proc; ///< Proc that is called when done (can be NULL)
gw_abort_proc *abortp; ///< Proc that is called when aborting (can be NULL)
- OTTDThread *thread; ///< The thread we are in (can be NULL)
+ class ThreadObject *thread; ///< The thread we are in (can be NULL)
};
-#ifdef TEMPORARY_OTTDTHREAD_DEFINITION
-#undef OTTDThread
-#undef TEMPORARY_OTTDTHREAD_DEFINITION
-#endif
-
enum gwp_class {
GWP_MAP_INIT, ///< Initialize/allocate the map, start economy
GWP_LANDSCAPE, ///< Create the landscape
--- a/src/group_cmd.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/group_cmd.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -39,7 +39,7 @@
/* Decrease the num engines of EngineID i of the old group if it's not the default one */
if (!IsDefaultGroupID(old_g) && IsValidGroupID(old_g)) GetGroup(old_g)->num_engines[i]--;
- /* Increase the num engines of EngineID i of the new group if it's not the new one */
+ /* Increase the num engines of EngineID i of the new group if it's not the default one */
if (!IsDefaultGroupID(new_g) && IsValidGroupID(new_g)) GetGroup(new_g)->num_engines[i]++;
}
}
--- a/src/lang/english.txt Wed Apr 16 22:16:04 2008 +0000
+++ b/src/lang/english.txt Wed Apr 16 22:34:14 2008 +0000
@@ -1363,6 +1363,8 @@
STR_NETWORK_GAME_NAME_TIP :{BLACK}Name of the game
STR_NETWORK_INFO_ICONS_TIP :{BLACK}Language, server version, etc.
STR_NETWORK_CLICK_GAME_TO_SELECT :{BLACK}Click a game from the list to select it
+STR_NETWORK_LAST_JOINED_SERVER :{BLACK}The server you joined last time:
+STR_NETWORK_CLICK_TO_SELECT_LAST :{BLACK}Click to select the server you played last time
STR_NETWORK_FIND_SERVER :{BLACK}Find server
STR_NETWORK_FIND_SERVER_TIP :{BLACK}Search network for a server
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/misc/smallvec.h Wed Apr 16 22:34:14 2008 +0000
@@ -0,0 +1,64 @@
+/* $Id$ */
+
+/* @file smallvec.h */
+
+#ifndef SMALLVEC_H
+#define SMALLVEC_H
+
+template <typename T, uint S> struct SmallVector {
+ T *data;
+ uint items;
+ uint capacity;
+
+ SmallVector() : data(NULL), items(0), capacity(0) { }
+
+ ~SmallVector()
+ {
+ free(data);
+ }
+
+ /**
+ * Append an item and return it.
+ */
+ T *Append()
+ {
+ if (items == capacity) {
+ capacity += S;
+ data = ReallocT(data, capacity);
+ }
+
+ return &data[items++];
+ }
+
+ const T *Begin() const
+ {
+ return data;
+ }
+
+ T *Begin()
+ {
+ return data;
+ }
+
+ const T *End() const
+ {
+ return &data[items];
+ }
+
+ T *End()
+ {
+ return &data[items];
+ }
+
+ const T *Get(size_t index) const
+ {
+ return &data[index];
+ }
+
+ T *Get(size_t index)
+ {
+ return &data[index];
+ }
+};
+
+#endif /* SMALLVEC_H */
--- a/src/network/network_gamelist.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/network/network_gamelist.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -25,6 +25,8 @@
* @return a point to the newly added or already existing item */
NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port)
{
+ if (ip == 0) return NULL;
+
NetworkGameList *item, *prev_item;
prev_item = NULL;
--- a/src/network/network_gui.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/network/network_gui.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -233,6 +233,9 @@
NGWW_MATRIX, ///< Panel with list of games
NGWW_SCROLLBAR, ///< Scrollbar of matrix
+ NGWW_LASTJOINED_LABEL, ///< Label "Last joined server:"
+ NGWW_LASTJOINED, ///< Info about the last joined server
+
NGWW_DETAILS, ///< Panel with game details
NGWW_JOIN, ///< 'Join game' button
NGWW_REFRESH, ///< 'Refresh server' button
@@ -245,6 +248,39 @@
};
/**
+ * Draw a single server line.
+ * @param cur_item the server to draw.
+ * @param y from where to draw?
+ * @param highlight does the line need to be highlighted?
+ */
+static void DrawServerLine(const Window *w, const NetworkGameList *cur_item, uint y, bool highlight)
+{
+ /* show highlighted item with a different colour */
+ if (highlight) GfxFillRect(w->widget[NGWW_NAME].left + 1, y - 2, w->widget[NGWW_INFO].right - 1, y + 9, 10);
+
+ SetDParamStr(0, cur_item->info.server_name);
+ DrawStringTruncated(w->widget[NGWW_NAME].left + 5, y, STR_02BD, TC_BLACK, w->widget[NGWW_NAME].right - w->widget[NGWW_NAME].left - 5);
+
+ SetDParam(0, cur_item->info.clients_on);
+ SetDParam(1, cur_item->info.clients_max);
+ SetDParam(2, cur_item->info.companies_on);
+ SetDParam(3, cur_item->info.companies_max);
+ DrawStringCentered(w->widget[NGWW_CLIENTS].left + 39, y, STR_NETWORK_GENERAL_ONLINE, TC_GOLD);
+
+ /* only draw icons if the server is online */
+ if (cur_item->online) {
+ /* draw a lock if the server is password protected */
+ if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, w->widget[NGWW_INFO].left + 5, y - 1);
+
+ /* draw red or green icon, depending on compatibility with server */
+ DrawSprite(SPR_BLOT, (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), w->widget[NGWW_INFO].left + 15, y);
+
+ /* draw flag according to server language */
+ DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, w->widget[NGWW_INFO].left + 25, y);
+ }
+}
+
+/**
* Handler of actions done in the NetworkStartServer window
*
* @param w pointer to the Window structure
@@ -261,7 +297,7 @@
switch (e->event) {
case WE_CREATE: // Focus input box
- w->vscroll.cap = 13;
+ w->vscroll.cap = 11;
w->resize.step_height = NET_PRC__SIZE_OF_ROW;
nd->field = NGWW_PLAYER;
@@ -314,7 +350,6 @@
uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
int32 n = 0;
int32 pos = w->vscroll.pos;
- uint max_name_width = w->widget[NGWW_NAME].right - w->widget[NGWW_NAME].left - 5;
const NetworkGameList *cur_item = _network_game_list;
while (pos > 0 && cur_item != NULL) {
@@ -323,35 +358,17 @@
}
while (cur_item != NULL) {
- /* show highlighted item with a different colour */
- if (cur_item == sel) GfxFillRect(w->widget[NGWW_NAME].left + 1, y - 2, w->widget[NGWW_INFO].right - 1, y + 9, 10);
-
- SetDParamStr(0, cur_item->info.server_name);
- DrawStringTruncated(w->widget[NGWW_NAME].left + 5, y, STR_02BD, TC_BLACK, max_name_width);
-
- SetDParam(0, cur_item->info.clients_on);
- SetDParam(1, cur_item->info.clients_max);
- SetDParam(2, cur_item->info.companies_on);
- SetDParam(3, cur_item->info.companies_max);
- DrawStringCentered(w->widget[NGWW_CLIENTS].left + 39, y, STR_NETWORK_GENERAL_ONLINE, TC_GOLD);
-
- /* only draw icons if the server is online */
- if (cur_item->online) {
- /* draw a lock if the server is password protected */
- if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, w->widget[NGWW_INFO].left + 5, y - 1);
-
- /* draw red or green icon, depending on compatibility with server */
- DrawSprite(SPR_BLOT, (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), w->widget[NGWW_INFO].left + 15, y);
-
- /* draw flag according to server language */
- DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, w->widget[NGWW_INFO].left + 25, y);
- }
+ DrawServerLine(w, cur_item, y, cur_item == sel);
cur_item = cur_item->next;
y += NET_PRC__SIZE_OF_ROW;
if (++n == w->vscroll.cap) break; // max number of games in the window
}
+ const NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_network_last_host), _network_last_port);
+ /* Draw the last joined server, if any */
+ if (last_joined != NULL) DrawServerLine(w, last_joined, y = w->widget[NGWW_LASTJOINED].top + 3, last_joined == sel);
+
/* Draw the right menu */
GfxFillRect(w->widget[NGWW_DETAILS].left + 1, 43, w->widget[NGWW_DETAILS].right - 1, 92, 157);
if (sel == NULL) {
@@ -467,6 +484,14 @@
SetWindowDirty(w);
} break;
+ case NGWW_LASTJOINED: {
+ NetworkGameList *last_joined = NetworkGameListAddItem(inet_addr(_network_last_host), _network_last_port);
+ if (last_joined != NULL) {
+ nd->server = last_joined;
+ SetWindowDirty(w);
+ }
+ } break;
+
case NGWW_FIND: // Find server automatically
switch (_network_lan_internet) {
case 0: NetworkUDPSearchGame(); break;
@@ -597,8 +622,10 @@
{ WWT_PUSHTXTBTN, RESIZE_LR, BTC, 71, 150, 42, 53, STR_NETWORK_CLIENTS_CAPTION, STR_NETWORK_CLIENTS_CAPTION_TIP}, // NGWW_CLIENTS
{ WWT_PUSHTXTBTN, RESIZE_LR, BTC, 151, 190, 42, 53, STR_EMPTY, STR_NETWORK_INFO_ICONS_TIP}, // NGWW_INFO
-{ WWT_MATRIX, RESIZE_RB, BGC, 10, 190, 54, 236, (11 << 8) + 1, STR_NETWORK_CLICK_GAME_TO_SELECT}, // NGWW_MATRIX
-{ WWT_SCROLLBAR, RESIZE_LRB, BGC, 191, 202, 42, 236, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // NGWW_SCROLLBAR
+{ WWT_MATRIX, RESIZE_RB, BGC, 10, 190, 54, 208, (11 << 8) + 1, STR_NETWORK_CLICK_GAME_TO_SELECT}, // NGWW_MATRIX
+{ WWT_SCROLLBAR, RESIZE_LRB, BGC, 191, 202, 42, 208, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // NGWW_SCROLLBAR
+{ WWT_TEXT, RESIZE_RTB, BGC, 10, 190, 211, 222, STR_NETWORK_LAST_JOINED_SERVER, STR_NULL}, // NGWW_LASTJOINED_LABEL
+{ WWT_PANEL, RESIZE_RTB, BGC, 10, 190, 223, 236, 0x0, STR_NETWORK_CLICK_TO_SELECT_LAST}, // NGWW_LASTJOINED
/* RIGHT SIDE */
{ WWT_PANEL, RESIZE_LRB, BGC, 210, 440, 42, 236, 0x0, STR_NULL}, // NGWW_DETAILS
--- a/src/newgrf_town.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/newgrf_town.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -36,16 +36,16 @@
case 0x8A: return t->grow_counter;
case 0x92: return t->flags12; // In original game, 0x92 and 0x93 are really one word. Since flags12 is a byte, this is to adjust
case 0x93: return 0;
- case 0x94: return t->radius[0];
- case 0x95: return GB(t->radius[0], 8, 8);
- case 0x96: return t->radius[1];
- case 0x97: return GB(t->radius[1], 8, 8);
- case 0x98: return t->radius[2];
- case 0x99: return GB(t->radius[2], 8, 8);
- case 0x9A: return t->radius[3];
- case 0x9B: return GB(t->radius[3], 8, 8);
- case 0x9C: return t->radius[4];
- case 0x9D: return GB(t->radius[4], 8, 8);
+ case 0x94: return ClampToU16(t->squared_town_zone_radius[0]);
+ case 0x95: return GB(ClampToU16(t->squared_town_zone_radius[0]), 8, 8);
+ case 0x96: return ClampToU16(t->squared_town_zone_radius[1]);
+ case 0x97: return GB(ClampToU16(t->squared_town_zone_radius[1]), 8, 8);
+ case 0x98: return ClampToU16(t->squared_town_zone_radius[2]);
+ case 0x99: return GB(ClampToU16(t->squared_town_zone_radius[2]), 8, 8);
+ case 0x9A: return ClampToU16(t->squared_town_zone_radius[3]);
+ case 0x9B: return GB(ClampToU16(t->squared_town_zone_radius[3]), 8, 8);
+ case 0x9C: return ClampToU16(t->squared_town_zone_radius[4]);
+ case 0x9D: return GB(ClampToU16(t->squared_town_zone_radius[4]), 8, 8);
case 0x9E: return t->ratings[0];
case 0x9F: return GB(t->ratings[0], 8, 8);
case 0xA0: return t->ratings[1];
--- a/src/order_cmd.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/order_cmd.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -1614,7 +1614,7 @@
}
/* Check if we've reached a non-stop station.. */
- if ((v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
+ if (v->current_order.IsType(OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
IsTileType(v->tile, MP_STATION) &&
v->current_order.GetDestination() == GetStationIndex(v->tile)) {
v->last_station_visited = v->current_order.GetDestination();
@@ -1742,10 +1742,11 @@
*/
bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
{
+ bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
return
v->last_station_visited != station && // Do stop only when we've not just been there
/* Finally do stop when there is no non-stop flag set for this type of station. */
- !(this->GetNonStopType() & ((this->dest == station) ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
+ !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
}
void InitializeOrders()
--- a/src/saveload.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/saveload.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -76,13 +76,24 @@
enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2};
+/** Error handler, calls longjmp to simulate an exception.
+ * @todo this was used to have a central place to handle errors, but it is
+ * pretty ugly, and seriously interferes with any multithreaded approaches */
+static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
+{
+ _sl.error_str = string;
+ free(_sl.extra_msg);
+ _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
+ throw std::exception();
+}
+
/**
* Fill the input buffer by reading from the file with the given reader
*/
static void SlReadFill()
{
uint len = _sl.read_bytes();
- assert(len != 0);
+ if (len == 0) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected end of chunk");
_sl.bufp = _sl.buf;
_sl.bufe = _sl.buf + len;
@@ -137,17 +148,6 @@
_sl.bufe = _sl.buf + _sl.bufsize;
}
-/** Error handler, calls longjmp to simulate an exception.
- * @todo this was used to have a central place to handle errors, but it is
- * pretty ugly, and seriously interferes with any multithreaded approaches */
-static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
-{
- _sl.error_str = string;
- free(_sl.extra_msg);
- _sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
- throw std::exception();
-}
-
/** Read in a single byte from file. If the temporary buffer is full,
* flush it to its final destination
* @return return the read byte from file
@@ -1499,7 +1499,7 @@
SaveFileDone();
}
-static OTTDThread* save_thread;
+static ThreadObject *save_thread;
/** We have written the whole game into memory, _Savegame_pool, now find
* and appropiate compressor and start writing to file.
@@ -1524,7 +1524,7 @@
uint i;
uint count = 1 << Savegame_POOL_BLOCK_SIZE_BITS;
- assert(_ts.count == _sl.offs_base);
+ if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
for (i = 0; i != _Savegame_pool.GetBlockCount() - 1; i++) {
_sl.buf = _Savegame_pool.blocks[i];
fmt->writer(count);
@@ -1537,7 +1537,7 @@
}
fmt->uninit_write();
- assert(_ts.count == _sl.offs_base);
+ if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
fclose(_sl.fh);
@@ -1561,7 +1561,7 @@
}
}
-static void* SaveFileToDiskThread(void *arg)
+static void * CDECL SaveFileToDiskThread(void *arg)
{
SaveFileToDisk(true);
return NULL;
@@ -1569,7 +1569,9 @@
void WaitTillSaved()
{
- OTTDJoinThread(save_thread);
+ if (save_thread == NULL) return;
+
+ save_thread->Join();
save_thread = NULL;
}
@@ -1641,7 +1643,7 @@
SaveFileStart();
if (_network_server ||
- (save_thread = OTTDCreateThread(&SaveFileToDiskThread, NULL)) == NULL) {
+ (save_thread = ThreadObject::New(&SaveFileToDiskThread, NULL)) == NULL) {
if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
SaveOrLoadResult result = SaveFileToDisk(false);
--- a/src/settings.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/settings.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -1339,6 +1339,8 @@
SDTG_VAR("min_players", SLE_UINT8, S, 0, _network_min_players, 0, 0, 10, 0, STR_NULL, NULL),
SDTG_OMANY("server_lang", SLE_UINT8, S, 0, _network_game_info.server_lang, 0, 35, "ANY|ENGLISH|GERMAN|FRENCH|BRAZILIAN|BULGARIAN|CHINESE|CZECH|DANISH|DUTCH|ESPERANTO|FINNISH|HUNGARIAN|ICELANDIC|ITALIAN|JAPANESE|KOREAN|LITHUANIAN|NORWEGIAN|POLISH|PORTUGUESE|ROMANIAN|RUSSIAN|SLOVAK|SLOVENIAN|SPANISH|SWEDISH|TURKISH|UKRAINIAN|AFRIKAANS|CROATIAN|CATALAN|ESTONIAN|GALICIAN|GREEK|LATVIAN", STR_NULL, NULL),
SDTG_BOOL("reload_cfg", S, 0, _network_reload_cfg, false, STR_NULL, NULL),
+ SDTG_STR("last_host", SLE_STRB, S, 0, _network_last_host, "0.0.0.0", STR_NULL, NULL),
+ SDTG_VAR("last_port", SLE_UINT16, S, 0, _network_last_port, 0, 0, UINT16_MAX, 0, STR_NULL ,NULL),
SDTG_END()
};
#endif /* ENABLE_NETWORK */
--- a/src/sound/win32_s.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/sound/win32_s.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -59,7 +59,7 @@
wfex.nBlockAlign = (wfex.nChannels * wfex.wBitsPerSample) / 8;
wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
- _bufsize = GetDriverParamInt(parm, "bufsize", 2048);
+ _bufsize = GetDriverParamInt(parm, "bufsize", (GB(GetVersion(), 0, 8) > 5) ? 2048 : 1024);
if (waveOutOpen(&_waveout, WAVE_MAPPER, &wfex, (DWORD_PTR)&waveOutProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
return "waveOutOpen failed";
--- a/src/thread.cpp Wed Apr 16 22:16:04 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,313 +0,0 @@
-/* $Id$ */
-
-/** @file thread.cpp */
-
-#include "stdafx.h"
-#include "thread.h"
-#include "core/alloc_func.hpp"
-#include <stdlib.h>
-
-#if defined(__AMIGA__) || defined(PSP) || defined(NO_THREADS)
-OTTDThread *OTTDCreateThread(OTTDThreadFunc function, void *arg) { return NULL; }
-void *OTTDJoinThread(OTTDThread *t) { return NULL; }
-void OTTDExitThread() { NOT_REACHED(); };
-
-#elif defined(__OS2__)
-
-#define INCL_DOS
-#include <os2.h>
-#include <process.h>
-
-struct OTTDThread {
- TID thread;
- OTTDThreadFunc func;
- void* arg;
- void* ret;
-};
-
-static void Proxy(void* arg)
-{
- OTTDThread* t = (OTTDThread*)arg;
- t->ret = t->func(t->arg);
-}
-
-OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
-{
- OTTDThread* t = MallocT<OTTDThread>(1);
-
- if (t == NULL) return NULL;
-
- t->func = function;
- t->arg = arg;
- t->thread = _beginthread(Proxy, NULL, 32768, t);
- if (t->thread != (TID)-1) {
- return t;
- } else {
- free(t);
- return NULL;
- }
-}
-
-void* OTTDJoinThread(OTTDThread* t)
-{
- void* ret;
-
- if (t == NULL) return NULL;
-
- DosWaitThread(&t->thread, DCWW_WAIT);
- ret = t->ret;
- free(t);
- return ret;
-}
-
-void OTTDExitThread()
-{
- _endthread();
-}
-
-#elif defined(UNIX) && !defined(MORPHOS)
-
-#include <pthread.h>
-
-struct OTTDThread {
- pthread_t thread;
-};
-
-OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
-{
- OTTDThread* t = MallocT<OTTDThread>(1);
-
- if (t == NULL) return NULL;
-
- if (pthread_create(&t->thread, NULL, function, arg) == 0) {
- return t;
- } else {
- free(t);
- return NULL;
- }
-}
-
-void* OTTDJoinThread(OTTDThread* t)
-{
- void* ret;
-
- if (t == NULL) return NULL;
-
- pthread_join(t->thread, &ret);
- free(t);
- return ret;
-}
-
-void OTTDExitThread()
-{
- pthread_exit(NULL);
-}
-
-#elif defined(WIN32)
-
-#include <windows.h>
-
-struct OTTDThread {
- HANDLE thread;
- OTTDThreadFunc func;
- void* arg;
- void* ret;
-};
-
-static DWORD WINAPI Proxy(LPVOID arg)
-{
- OTTDThread* t = (OTTDThread*)arg;
- t->ret = t->func(t->arg);
- return 0;
-}
-
-OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void* arg)
-{
- OTTDThread* t = MallocT<OTTDThread>(1);
- DWORD dwThreadId;
-
- if (t == NULL) return NULL;
-
- t->func = function;
- t->arg = arg;
- t->thread = CreateThread(NULL, 0, Proxy, t, 0, &dwThreadId);
-
- if (t->thread != NULL) {
- return t;
- } else {
- free(t);
- return NULL;
- }
-}
-
-void* OTTDJoinThread(OTTDThread* t)
-{
- void* ret;
-
- if (t == NULL) return NULL;
-
- WaitForSingleObject(t->thread, INFINITE);
- CloseHandle(t->thread);
- ret = t->ret;
- free(t);
- return ret;
-}
-
-void OTTDExitThread()
-{
- ExitThread(0);
-}
-
-
-#elif defined(MORPHOS)
-
-#include <exec/types.h>
-#include <exec/rawfmt.h>
-#include <dos/dostags.h>
-
-#include <proto/dos.h>
-#include <proto/exec.h>
-
-#include <setjmp.h>
-
-/* NOTE: this code heavily depends on latest libnix updates. So make
- * sure you link with new stuff which supports semaphore locking of
- * the IO resources, else it will just go foobar. */
-
-struct OTTDThreadStartupMessage {
- struct Message msg; ///< standard exec.library message (MUST be the first thing in the message struct!)
- OTTDThreadFunc func; ///< function the thread will execute
- void *arg; ///< functions arguments for the thread function
- void *ret; ///< return value of the thread function
- jmp_buf jumpstore; ///< storage for the setjump state
-};
-
-struct OTTDThread {
- struct MsgPort *replyport;
- struct OTTDThreadStartupMessage msg;
-};
-
-
-/**
- * Default OpenTTD STDIO/ERR debug output is not very useful for this, so we
- * utilize serial/ramdebug instead.
- */
-#ifndef NO_DEBUG_MESSAGES
-void KPutStr(CONST_STRPTR format)
-{
- RawDoFmt(format, NULL, (void (*)())RAWFMTFUNC_SERIAL, NULL);
-}
-#else
-#define KPutStr(x)
-#endif
-
-static void Proxy(void)
-{
- struct Task *child = FindTask(NULL);
- struct OTTDThreadStartupMessage *msg;
-
- /* Make sure, we don't block the parent. */
- SetTaskPri(child, -5);
-
- KPutStr("[Child] Progressing...\n");
-
- if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
- /* Make use of setjmp() here, so this point can be reached again from inside
- * OTTDExitThread() which can be called from anythere inside msg->func.
- * It's a bit ugly and in worst case it leaks some memory. */
- if (setjmp(msg->jumpstore) == 0) {
- msg->ret = msg->func(msg->arg);
- } else {
- KPutStr("[Child] Returned to main()\n");
- }
- }
-
- /* Quit the child, exec.library will reply the startup msg internally. */
- KPutStr("[Child] Done.\n");
-}
-
-OTTDThread* OTTDCreateThread(OTTDThreadFunc function, void *arg)
-{
- OTTDThread *t;
- struct Task *parent;
-
- KPutStr("[OpenTTD] Create thread...\n");
-
- t = (struct OTTDThread *)AllocVecTaskPooled(sizeof(struct OTTDThread));
- if (t == NULL) return NULL;
-
- parent = FindTask(NULL);
-
- /* Make sure main thread runs with sane priority */
- SetTaskPri(parent, 0);
-
- /* Things we'll pass down to the child by utilizing NP_StartupMsg */
- t->msg.func = function;
- t->msg.arg = arg;
- t->msg.ret = NULL;
-
- t->replyport = CreateMsgPort();
-
- if (t->replyport != NULL) {
- struct Process *child;
-
- t->msg.msg.mn_Node.ln_Type = NT_MESSAGE;
- t->msg.msg.mn_ReplyPort = t->replyport;
- t->msg.msg.mn_Length = sizeof(struct OTTDThreadStartupMessage);
-
- child = CreateNewProcTags(
- NP_CodeType, CODETYPE_PPC,
- NP_Entry, Proxy,
- NP_StartupMsg, (ULONG)&t->msg,
- NP_Priority, 5UL,
- NP_Name, (ULONG)"OpenTTD Thread",
- NP_PPCStackSize, 131072UL,
- TAG_DONE);
-
- if (child != NULL) {
- KPutStr("[OpenTTD] Child process launched.\n");
- return t;
- }
- DeleteMsgPort(t->replyport);
- }
- FreeVecTaskPooled(t);
-
- return NULL;
-}
-
-void* OTTDJoinThread(OTTDThread *t)
-{
- struct OTTDThreadStartupMessage *reply;
- void *ret;
-
- KPutStr("[OpenTTD] Join threads...\n");
-
- if (t == NULL) return NULL;
-
- KPutStr("[OpenTTD] Wait for child to quit...\n");
- WaitPort(t->replyport);
-
- reply = (struct OTTDThreadStartupMessage *)GetMsg(t->replyport);
- ret = reply->ret;
-
- DeleteMsgPort(t->replyport);
- FreeVecTaskPooled(t);
-
- return ret;
-}
-
-void OTTDExitThread()
-{
- struct OTTDThreadStartupMessage *msg;
-
- KPutStr("[Child] Aborting...\n");
-
- if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
- KPutStr("[Child] Jumping back...\n");
- longjmp(msg->jumpstore, 0xBEAFCAFE);
- }
-
- NOT_REACHED();
-}
-
-#endif
--- a/src/thread.h Wed Apr 16 22:16:04 2008 +0000
+++ b/src/thread.h Wed Apr 16 22:34:14 2008 +0000
@@ -5,12 +5,95 @@
#ifndef THREAD_H
#define THREAD_H
-struct OTTDThread;
+typedef void * (CDECL *OTTDThreadFunc)(void *);
-typedef void * (*OTTDThreadFunc)(void*);
+/**
+ * A Thread Object which works on all our supported OSes.
+ */
+class ThreadObject {
+public:
+ /**
+ * Virtual destructor to allow 'delete' operator to work properly.
+ */
+ virtual ~ThreadObject() {};
-OTTDThread *OTTDCreateThread(OTTDThreadFunc, void*);
-void *OTTDJoinThread(OTTDThread*);
-void OTTDExitThread();
+ /**
+ * Check if the thread is currently running.
+ * @return True if the thread is running.
+ */
+ virtual bool IsRunning() = 0;
+
+ /**
+ * Waits for the thread to exit.
+ * @return True if the thread has exited.
+ */
+ virtual bool WaitForStop() = 0;
+
+ /**
+ * Exit this thread.
+ */
+ virtual bool Exit() = 0;
+
+ /**
+ * Join this thread.
+ */
+ virtual void *Join() = 0;
+
+ /**
+ * Check if this thread is the current active thread.
+ * @return True if it is the current active thread.
+ */
+ virtual bool IsCurrent() = 0;
+
+ /**
+ * Get the unique ID of this thread.
+ * @return A value unique to each thread.
+ */
+ virtual uint GetId() = 0;
+
+ /**
+ * Create a thread; proc will be called as first function inside the thread,
+ * with optinal params.
+ * @param proc The procedure to call inside the thread.
+ * @param param The params to give with 'proc'.
+ * @return True if the thread was started correctly.
+ */
+ static ThreadObject *New(OTTDThreadFunc proc, void *param);
+
+ /**
+ * Convert the current thread to a new ThreadObject.
+ * @return A new ThreadObject with the current thread attached to it.
+ */
+ static ThreadObject* AttachCurrent();
+
+ /**
+ * Find the Id of the current running thread.
+ * @return The thread ID of the current active thread.
+ */
+ static uint CurrentId();
+};
+
+/**
+ * Cross-platform Thread Semaphore. Wait() waits for a Set() of someone else.
+ */
+class ThreadSemaphore {
+public:
+ static ThreadSemaphore *New();
+
+ /**
+ * Virtual Destructor to avoid compiler warnings.
+ */
+ virtual ~ThreadSemaphore() {};
+
+ /**
+ * Signal all threads that are in Wait() to continue.
+ */
+ virtual void Set() = 0;
+
+ /**
+ * Wait until we are signaled by a call to Set().
+ */
+ virtual void Wait() = 0;
+};
#endif /* THREAD_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/thread_none.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -0,0 +1,42 @@
+/* $Id$ */
+
+/** @file thread_none.cpp No-Threads-Available implementation of Threads */
+
+#include "stdafx.h"
+#include "thread.h"
+#include "fiber.hpp"
+
+/* static */ ThreadObject *ThreadObject::New(OTTDThreadFunc proc, void *param)
+{
+ return NULL;
+}
+
+/* static */ ThreadObject *ThreadObject::AttachCurrent()
+{
+ return NULL;
+}
+
+/* static */ uint ThreadObject::CurrentId()
+{
+ return -1;
+}
+
+/* static */ ThreadSemaphore *ThreadSemaphore::New()
+{
+ return NULL;
+}
+
+/* static */ Fiber *Fiber::New(FiberFunc proc, void *param)
+{
+ return NULL;
+}
+
+/* static */ Fiber *Fiber::AttachCurrent(void *param)
+{
+ return NULL;
+}
+
+/* static */ void *Fiber::GetCurrentFiberData()
+{
+ return NULL;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/thread_os2.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -0,0 +1,80 @@
+/* $Id$ */
+
+/** @file thread_os2.cpp OS2 implementation of Threads. */
+
+#include "stdafx.h"
+#include "thread.h"
+
+#if 0
+#include "debug.h"
+#include "core/alloc_func.hpp"
+#include <stdlib.h>
+
+#define INCL_DOS
+#include <os2.h>
+#include <process.h>
+
+struct OTTDThread {
+ TID thread;
+ OTTDThreadFunc func;
+ void *arg;
+ void *ret;
+};
+
+static void Proxy(void *arg)
+{
+ OTTDThread *t = (OTTDThread *)arg;
+ t->ret = t->func(t->arg);
+}
+
+OTTDThread *OTTDCreateThread(OTTDThreadFunc function, void *arg)
+{
+ OTTDThread *t = MallocT<OTTDThread>(1);
+
+ t->func = function;
+ t->arg = arg;
+ t->thread = _beginthread(Proxy, NULL, 32768, t);
+ if (t->thread != (TID)-1) {
+ return t;
+ } else {
+ free(t);
+ return NULL;
+ }
+}
+
+void *OTTDJoinThread(OTTDThread *t)
+{
+ if (t == NULL) return NULL;
+
+ DosWaitThread(&t->thread, DCWW_WAIT);
+ void *ret = t->ret;
+ free(t);
+ return ret;
+}
+
+void OTTDExitThread()
+{
+ _endthread();
+}
+
+#endif
+
+/* static */ ThreadObject *ThreadObject::New(OTTDThreadFunc proc, void *param)
+{
+ return NULL;
+}
+
+/* static */ ThreadObject *ThreadObject::AttachCurrent()
+{
+ return NULL;
+}
+
+/* static */ uint ThreadObject::CurrentId()
+{
+ return -1;
+}
+
+/* static */ ThreadSemaphore *ThreadSemaphore::New()
+{
+ return NULL;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/thread_pthread.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -0,0 +1,199 @@
+/* $Id$ */
+
+/** @file thread_pthread.cpp POSIX pthread implementation of Threads. */
+
+#include "stdafx.h"
+#include "thread.h"
+#include "debug.h"
+#include "core/alloc_func.hpp"
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <unistd.h>
+
+/**
+ * POSIX pthread version for ThreadObject.
+ */
+class ThreadObject_pthread : public ThreadObject {
+private:
+ pthread_t m_thr; ///< System thread identifier.
+ OTTDThreadFunc m_proc; ///< External thread procedure.
+ void *m_param; ///< Parameter for the external thread procedure.
+ bool m_attached; ///< True if the ThreadObject was attached to an existing thread.
+ sem_t m_sem_start; ///< Here the new thread waits before it starts.
+ sem_t m_sem_stop; ///< Here the other thread can wait for this thread to end.
+
+public:
+ /**
+ * Create a pthread and start it, calling proc(param).
+ */
+ ThreadObject_pthread(OTTDThreadFunc proc, void *param) :
+ m_thr(0),
+ m_proc(proc),
+ m_param(param),
+ m_attached(false)
+ {
+ sem_init(&m_sem_start, 0, 0);
+ sem_init(&m_sem_stop, 0, 0);
+
+ pthread_create(&m_thr, NULL, &stThreadProc, this);
+ sem_post(&m_sem_start);
+ }
+
+ /**
+ * Create a pthread and attach current thread to it.
+ */
+ ThreadObject_pthread() :
+ m_thr(0),
+ m_proc(NULL),
+ m_param(0),
+ m_attached(true)
+ {
+ sem_init(&m_sem_start, 0, 0);
+ sem_init(&m_sem_stop, 0, 0);
+
+ m_thr = pthread_self();
+ }
+
+ /* virtual */ ~ThreadObject_pthread()
+ {
+ sem_destroy(&m_sem_stop);
+ sem_destroy(&m_sem_start);
+ };
+
+ /* virtual */ bool IsRunning()
+ {
+ return m_thr != 0;
+ }
+
+ /* virtual */ bool WaitForStop()
+ {
+ /* You can't wait on yourself */
+ assert(!IsCurrent());
+ /* If the thread is not running, waiting is over */
+ if (!IsRunning()) return true;
+
+ int ret = sem_wait(&m_sem_stop);
+ if (ret == 0) {
+ /* We have passed semaphore so increment it again */
+ sem_post(&m_sem_stop);
+ return true;
+ }
+ return false;
+ }
+
+ /* virtual */ bool Exit()
+ {
+ /* You can only exit yourself */
+ assert(IsCurrent());
+ /* If the thread is not running, we are already closed */
+ if (!IsRunning()) return false;
+
+ /* For now we terminate by throwing an error, gives much cleaner cleanup */
+ throw 0;
+ }
+
+ /* virtual */ void *Join()
+ {
+ /* You cannot join yourself */
+ assert(!IsCurrent());
+
+ void *ret;
+ pthread_join(m_thr, &ret);
+ m_thr = 0;
+
+ return ret;
+ }
+
+ /* virtual */ bool IsCurrent()
+ {
+ return pthread_self() == m_thr;
+ }
+
+ /* virtual */ uint GetId()
+ {
+ return (uint)m_thr;
+ }
+
+private:
+ /**
+ * On thread creation, this function is called, which calls the real startup
+ * function. This to get back into the correct instance again.
+ */
+ static void *stThreadProc(void *thr)
+ {
+ return ((ThreadObject_pthread *)thr)->ThreadProc();
+ }
+
+ /**
+ * A new thread is created, and this function is called. Call the custom
+ * function of the creator of the thread.
+ */
+ void *ThreadProc()
+ {
+ /* The new thread stops here so the calling thread can complete pthread_create() call */
+ sem_wait(&m_sem_start);
+
+ /* Call the proc of the creator to continue this thread */
+ try {
+ m_proc(m_param);
+ } catch (...) {
+ }
+
+ /* Notify threads waiting for our completion */
+ sem_post(&m_sem_stop);
+
+ return NULL;
+ }
+};
+
+/* static */ ThreadObject *ThreadObject::New(OTTDThreadFunc proc, void *param)
+{
+ return new ThreadObject_pthread(proc, param);
+}
+
+/* static */ ThreadObject *ThreadObject::AttachCurrent()
+{
+ return new ThreadObject_pthread();
+}
+
+/* static */ uint ThreadObject::CurrentId()
+{
+ return (uint)pthread_self();
+}
+
+
+/**
+ * POSIX pthread version of ThreadSemaphore.
+ */
+class ThreadSemaphore_pthread : public ThreadSemaphore {
+private:
+ sem_t m_sem;
+
+public:
+ ThreadSemaphore_pthread()
+ {
+ sem_init(&m_sem, 0, 0);
+ }
+
+ /* virtual */ ~ThreadSemaphore_pthread()
+ {
+ sem_destroy(&m_sem);
+ }
+
+ /* virtual */ void Set()
+ {
+ int val = 0;
+ if (sem_getvalue(&m_sem, &val) == 0 && val == 0) sem_post(&m_sem);
+ }
+
+ /* virtual */ void Wait()
+ {
+ sem_wait(&m_sem);
+ }
+};
+
+/* static */ ThreadSemaphore *ThreadSemaphore::New()
+{
+ return new ThreadSemaphore_pthread();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/thread_win32.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -0,0 +1,188 @@
+/* $Id$ */
+
+/** @file thread_win32.cpp Win32 thread implementation of Threads. */
+
+#include "stdafx.h"
+#include "thread.h"
+#include "debug.h"
+#include "core/alloc_func.hpp"
+#include <stdlib.h>
+#include <windows.h>
+#include <process.h>
+
+/**
+ * Win32 thread version for ThreadObject.
+ */
+class ThreadObject_Win32 : public ThreadObject {
+private:
+ uint m_id_thr;
+ HANDLE m_h_thr;
+ OTTDThreadFunc m_proc;
+ void *m_param;
+ bool m_attached;
+ void *ret;
+
+public:
+ /**
+ * Create a win32 thread and start it, calling proc(param).
+ */
+ ThreadObject_Win32(OTTDThreadFunc proc, void *param) :
+ m_id_thr(0),
+ m_h_thr(NULL),
+ m_proc(proc),
+ m_param(param),
+ m_attached(false)
+ {
+ m_h_thr = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &m_id_thr);
+ if (m_h_thr == NULL) return;
+ ResumeThread(m_h_thr);
+ }
+
+ /**
+ * Create a win32 thread and attach current thread to it.
+ */
+ ThreadObject_Win32() :
+ m_id_thr(0),
+ m_h_thr(NULL),
+ m_proc(NULL),
+ m_param(NULL),
+ m_attached(false)
+ {
+ BOOL ret = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &m_h_thr, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (!ret) return;
+ m_id_thr = GetCurrentThreadId();
+ }
+
+ /* virtual */ ~ThreadObject_Win32()
+ {
+ if (m_h_thr != NULL) {
+ CloseHandle(m_h_thr);
+ m_h_thr = NULL;
+ }
+ }
+
+ /* virtual */ bool IsRunning()
+ {
+ if (m_h_thr == NULL) return false;
+ DWORD exit_code = 0;
+ if (!GetExitCodeThread(m_h_thr, &exit_code)) return false;
+ return (exit_code == STILL_ACTIVE);
+ }
+
+ /* virtual */ bool WaitForStop()
+ {
+ /* You can't wait on yourself */
+ assert(!IsCurrent());
+ /* If the thread is not running, waiting is over */
+ if (!IsRunning()) return true;
+
+ DWORD res = WaitForSingleObject(m_h_thr, INFINITE);
+ return res == WAIT_OBJECT_0;
+ }
+
+ /* virtual */ bool Exit()
+ {
+ /* You can only exit yourself */
+ assert(IsCurrent());
+ /* If the thread is not running, we are already closed */
+ if (!IsRunning()) return false;
+
+ /* For now we terminate by throwing an error, gives much cleaner cleanup */
+ throw 0;
+ }
+
+ /* virtual */ void *Join()
+ {
+ /* You cannot join yourself */
+ assert(!IsCurrent());
+
+ WaitForSingleObject(m_h_thr, INFINITE);
+
+ return this->ret;
+ }
+
+ /* virtual */ bool IsCurrent()
+ {
+ DWORD id_cur = GetCurrentThreadId();
+ return id_cur == m_id_thr;
+ }
+
+ /* virtual */ uint GetId()
+ {
+ return m_id_thr;
+ }
+
+private:
+ /**
+ * On thread creation, this function is called, which calls the real startup
+ * function. This to get back into the correct instance again.
+ */
+ static uint CALLBACK stThreadProc(void *thr)
+ {
+ return ((ThreadObject_Win32 *)thr)->ThreadProc();
+ }
+
+ /**
+ * A new thread is created, and this function is called. Call the custom
+ * function of the creator of the thread.
+ */
+ uint ThreadProc()
+ {
+ try {
+ this->ret = m_proc(m_param);
+ } catch (...) {
+ }
+
+ return 0;
+ }
+};
+
+/* static */ ThreadObject *ThreadObject::New(OTTDThreadFunc proc, void *param)
+{
+ return new ThreadObject_Win32(proc, param);
+}
+
+/* static */ ThreadObject* ThreadObject::AttachCurrent()
+{
+ return new ThreadObject_Win32();
+}
+
+/* static */ uint ThreadObject::CurrentId()
+{
+ return GetCurrentThreadId();
+}
+
+
+/**
+ * Win32 thread version of ThreadSemaphore.
+ */
+class ThreadSemaphore_Win32 : public ThreadSemaphore {
+private:
+ HANDLE m_handle;
+
+public:
+ ThreadSemaphore_Win32()
+ {
+ m_handle = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+ }
+
+ /* virtual */ ~ThreadSemaphore_Win32()
+ {
+ ::CloseHandle(m_handle);
+ }
+
+ /* virtual */ void Set()
+ {
+ ::SetEvent(m_handle);
+ }
+
+ /* virtual */ void Wait()
+ {
+ ::WaitForSingleObject(m_handle, INFINITE);
+ }
+};
+
+/* static */ ThreadSemaphore *ThreadSemaphore::New()
+{
+ return new ThreadSemaphore_Win32();
+}
--- a/src/town.h Wed Apr 16 22:16:04 2008 +0000
+++ b/src/town.h Wed Apr 16 22:34:14 2008 +0000
@@ -163,7 +163,7 @@
bool larger_town;
/* NOSAVE: UpdateTownRadius updates this given the house count. */
- uint16 radius[HZB_END];
+ uint32 squared_town_zone_radius[HZB_END];
/* NOSAVE: The number of each type of building in the town. */
BuildingCounts building_counts;
--- a/src/town_cmd.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/town_cmd.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -1301,7 +1301,7 @@
void UpdateTownRadius(Town *t)
{
- static const uint16 _town_radius_data[23][5] = {
+ static const uint32 _town_squared_town_zone_radius_data[23][5] = {
{ 4, 0, 0, 0, 0}, // 0
{ 16, 0, 0, 0, 0},
{ 25, 0, 0, 0, 0},
@@ -1328,19 +1328,17 @@
};
if (t->num_houses < 92) {
- memcpy(t->radius, _town_radius_data[t->num_houses / 4], sizeof(t->radius));
+ memcpy(t->squared_town_zone_radius, _town_squared_town_zone_radius_data[t->num_houses / 4], sizeof(t->squared_town_zone_radius));
} else {
int mass = t->num_houses / 8;
- /* At least very roughly extrapolate. Empirical numbers dancing between
- * overwhelming by cottages and skyscrapers outskirts. */
- t->radius[0] = mass * mass;
- /* Actually we are proportional to sqrt() but that's right because
- * we are covering an area. */
- t->radius[1] = mass * 7;
- t->radius[2] = 0;
- t->radius[3] = mass * 4;
- t->radius[4] = mass * 3;
- //debug("%d (->%d): %d %d %d %d\n", t->num_houses, mass, t->radius[0], t->radius[1], t->radius[3], t->radius[4]);
+ /* Actually we are proportional to sqrt() but that's right because we are covering an area.
+ * The offsets are to make sure the radii do not decrease in size when going from the table
+ * to the calculated value.*/
+ t->squared_town_zone_radius[0] = mass * 15 - 40;
+ t->squared_town_zone_radius[1] = mass * 9 - 15;
+ t->squared_town_zone_radius[2] = 0;
+ t->squared_town_zone_radius[3] = mass * 5 - 5;
+ t->squared_town_zone_radius[4] = mass * 3 + 5;
}
}
@@ -1603,8 +1601,8 @@
/** Returns the bit corresponding to the town zone of the specified tile
- * @param t Town on which radius is to be found
- * @param tile TileIndex where radius needs to be found
+ * @param t Town on which town zone is to be found
+ * @param tile TileIndex where town zone needs to be found
* @return the bit position of the given zone, as defined in HouseZones
*/
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile)
@@ -1615,7 +1613,7 @@
HouseZonesBits smallest = HZB_TOWN_EDGE;
for (HouseZonesBits i = HZB_BEGIN; i < HZB_END; i++) {
- if (dist < t->radius[i]) smallest = i;
+ if (dist < t->squared_town_zone_radius[i]) smallest = i;
}
return smallest;
@@ -1992,6 +1990,33 @@
DeleteAnimatedTile(tile);
}
+/**
+ * Determines if a given HouseID is part of a multitile house.
+ * The given ID is set to the ID of the north tile and the TileDiff to the north tile is returned.
+ *
+ * @param house Is changed to the HouseID of the north tile of the same house
+ * @return TileDiff from the tile of the given HouseID to the north tile
+ */
+static TileIndex GetHouseNorthPart(HouseID &house)
+{
+ if (house >= 3) { // house id 0,1,2 MUST be single tile houses, or this code breaks.
+ if (GetHouseSpecs(house - 1)->building_flags & TILE_SIZE_2x1) {
+ house--;
+ return TileDiffXY(-1, 0);
+ } else if (GetHouseSpecs(house - 1)->building_flags & BUILDING_2_TILES_Y) {
+ house--;
+ return TileDiffXY(0, -1);
+ } else if (GetHouseSpecs(house - 2)->building_flags & BUILDING_HAS_4_TILES) {
+ house -= 2;
+ return TileDiffXY(-1, 0);
+ } else if (GetHouseSpecs(house - 3)->building_flags & BUILDING_HAS_4_TILES) {
+ house -= 3;
+ return TileDiffXY(-1, -1);
+ }
+ }
+ return 0;
+}
+
void ClearTownHouse(Town *t, TileIndex tile)
{
assert(IsTileType(tile, MP_HOUSE));
@@ -1999,21 +2024,7 @@
HouseID house = GetHouseType(tile);
/* need to align the tile to point to the upper left corner of the house */
- if (house >= 3) { // house id 0,1,2 MUST be single tile houses, or this code breaks.
- if (GetHouseSpecs(house-1)->building_flags & TILE_SIZE_2x1) {
- house--;
- tile += TileDiffXY(-1, 0);
- } else if (GetHouseSpecs(house-1)->building_flags & BUILDING_2_TILES_Y) {
- house--;
- tile += TileDiffXY(0, -1);
- } else if (GetHouseSpecs(house-2)->building_flags & BUILDING_HAS_4_TILES) {
- house-=2;
- tile += TileDiffXY(-1, 0);
- } else if (GetHouseSpecs(house-3)->building_flags & BUILDING_HAS_4_TILES) {
- house-=3;
- tile += TileDiffXY(-1, -1);
- }
- }
+ tile += GetHouseNorthPart(house); // modifies house to the ID of the north tile
const HouseSpec *hs = GetHouseSpecs(house);
@@ -2285,7 +2296,7 @@
const Station *st;
FOR_ALL_STATIONS(st) {
- if (DistanceSquare(st->xy, t->xy) <= t->radius[0]) {
+ if (DistanceSquare(st->xy, t->xy) <= t->squared_town_zone_radius[0]) {
if (st->time_since_load <= 20 || st->time_since_unload <= 20) {
n++;
if (IsValidPlayer(st->owner)) {
@@ -2536,6 +2547,7 @@
{
if (AutoslopeEnabled()) {
HouseID house = GetHouseType(tile);
+ GetHouseNorthPart(house); // modifies house to the ID of the north tile
const HouseSpec *hs = GetHouseSpecs(house);
/* Here we differ from TTDP by checking TILE_NOT_SLOPED */
--- a/src/town_gui.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/town_gui.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -278,6 +278,7 @@
enum TownViewWidget {
TVW_CAPTION = 1,
+ TVW_STICKY,
TVW_CENTERVIEW = 6,
TVW_SHOWAUTORITY,
TVW_CHANGENAME,
@@ -290,9 +291,22 @@
Town *t = GetTown(w->window_number);
switch (e->event) {
- case WE_CREATE:
+ case WE_CREATE: {
+ bool ingame = _game_mode != GM_EDITOR;
if (t->larger_town) w->widget[TVW_CAPTION].data = STR_CITY;
- break;
+ w->SetWidgetHiddenState(TVW_DELETE, ingame); // hide delete button on game mode
+ w->SetWidgetHiddenState(TVW_EXPAND, ingame); // hide expand button on game mode
+ w->SetWidgetHiddenState(TVW_SHOWAUTORITY, !ingame); // hide autority button on editor mode
+
+ if (ingame) {
+ /* resize caption bar */
+ w->widget[TVW_CAPTION].right = w->widget[TVW_STICKY].left -1;
+ /* move the rename from top on scenario to bottom in game */
+ w->widget[TVW_CHANGENAME].top = w->widget[TVW_EXPAND].top;
+ w->widget[TVW_CHANGENAME].bottom = w->widget[TVW_EXPAND].bottom;
+ w->widget[TVW_CHANGENAME].right = w->widget[TVW_STICKY].right;
+ }
+ } break;
case WE_PAINT:
/* disable renaming town in network games if you are not the server */
@@ -353,14 +367,16 @@
static const Widget _town_view_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{ WWT_CAPTION, RESIZE_NONE, 13, 11, 247, 0, 13, STR_2005, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_CAPTION, RESIZE_NONE, 13, 11, 172, 0, 13, STR_2005, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, RESIZE_NONE, 13, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_PANEL, RESIZE_NONE, 13, 0, 259, 14, 105, 0x0, STR_NULL},
{ WWT_INSET, RESIZE_NONE, 13, 2, 257, 16, 103, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 13, 0, 259, 106, 137, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 85, 138, 149, STR_00E4_LOCATION, STR_200B_CENTER_THE_MAIN_VIEW_ON},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 86, 171, 138, 149, STR_2020_LOCAL_AUTHORITY, STR_2021_SHOW_INFORMATION_ON_LOCAL},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 172, 259, 138, 149, STR_0130_RENAME, STR_200C_CHANGE_TOWN_NAME},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 172, 247, 0, 13, STR_0130_RENAME, STR_200C_CHANGE_TOWN_NAME},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 86, 171, 138, 149, STR_023C_EXPAND, STR_023B_INCREASE_SIZE_OF_TOWN},
+{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 172, 259, 138, 149, STR_0290_DELETE, STR_0291_DELETE_THIS_TOWN_COMPLETELY},
{ WIDGETS_END},
};
@@ -372,38 +388,11 @@
TownViewWndProc
};
-static const Widget _town_view_scen_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{ WWT_CAPTION, RESIZE_NONE, 13, 11, 172, 0, 13, STR_2005, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_STICKYBOX, RESIZE_NONE, 13, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON},
-{ WWT_PANEL, RESIZE_NONE, 13, 0, 259, 14, 105, 0x0, STR_NULL},
-{ WWT_INSET, RESIZE_NONE, 13, 2, 257, 16, 103, 0x0, STR_NULL},
-{ WWT_PANEL, RESIZE_NONE, 13, 0, 259, 106, 137, 0x0, STR_NULL},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 85, 138, 149, STR_00E4_LOCATION, STR_200B_CENTER_THE_MAIN_VIEW_ON},
-{ WWT_EMPTY, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_NULL},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 173, 247, 0, 13, STR_0130_RENAME, STR_200C_CHANGE_TOWN_NAME},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 86, 171, 138, 149, STR_023C_EXPAND, STR_023B_INCREASE_SIZE_OF_TOWN},
-{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 172, 259, 138, 149, STR_0290_DELETE, STR_0291_DELETE_THIS_TOWN_COMPLETELY},
-{ WIDGETS_END},
-};
-
-static const WindowDesc _town_view_scen_desc = {
- WDP_AUTO, WDP_AUTO, 260, 150, 260, 150,
- WC_TOWN_VIEW, WC_NONE,
- WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
- _town_view_scen_widgets,
- TownViewWndProc
-};
-
void ShowTownViewWindow(TownID town)
{
Window *w;
- if (_game_mode != GM_EDITOR) {
- w = AllocateWindowDescFront(&_town_view_desc, town);
- } else {
- w = AllocateWindowDescFront(&_town_view_scen_desc, town);
- }
+ w = AllocateWindowDescFront(&_town_view_desc, town);
if (w != NULL) {
w->flags4 |= WF_DISABLE_VP_SCROLL;
--- a/src/train_cmd.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/train_cmd.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -1811,8 +1811,7 @@
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
}
- /* set reversed flag on all parts */
- for (Vehicle *u = v; u != NULL; u = u->Next()) ToggleBit(u->u.rail.flags, VRF_TOGGLE_REVERSE);
+ ToggleBit(v->u.rail.flags, VRF_TOGGLE_REVERSE);
ClrBit(v->u.rail.flags, VRF_REVERSING);
--- a/src/vehicle.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/vehicle.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -2188,8 +2188,7 @@
if (!IsFrontEngine(v)) v = v->First();
UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
v->load_unload_time_rem = 0;
- /* Reset reversed flag */
- for (Vehicle *u = v; u != NULL; u = u->Next()) ClrBit(u->u.rail.flags, VRF_TOGGLE_REVERSE);
+ ClrBit(v->u.rail.flags, VRF_TOGGLE_REVERSE);
TrainConsistChanged(v);
break;
--- a/src/vehicle_base.h Wed Apr 16 22:16:04 2008 +0000
+++ b/src/vehicle_base.h Wed Apr 16 22:34:14 2008 +0000
@@ -140,7 +140,7 @@
/* used to mark that electric train engine is allowed to run on normal rail */
VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6,
- /* used for vehicle var 0xFE bit 8 (toggled each time the train is reversed) */
+ /* used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle only) */
VRF_TOGGLE_REVERSE = 7,
};
--- a/src/viewport.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/viewport.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -29,15 +29,11 @@
#include "settings_type.h"
#include "station_func.h"
#include "core/alloc_type.hpp"
+#include "misc/smallvec.h"
#include "table/sprites.h"
#include "table/strings.h"
-enum {
- VIEWPORT_DRAW_MEM = (65536 * 2),
- PARENT_LIST_SIZE = 6144,
-};
-
PlaceProc *_place_proc;
Point _tile_fract_coords;
ZoomLevel _saved_scrollpos_zoom;
@@ -78,7 +74,6 @@
struct StringSpriteToDraw {
uint16 string;
uint16 color;
- StringSpriteToDraw *next;
int32 x;
int32 y;
uint64 params[2];
@@ -89,7 +84,6 @@
SpriteID image;
SpriteID pal;
const SubSprite *sub; ///< only draw a rectangular part of the sprite
- TileSpriteToDraw *next;
int32 x;
int32 y;
byte z;
@@ -122,18 +116,11 @@
int zmin; ///< minimal world Z coordinate of bounding box
int zmax; ///< maximal world Z coordinate of bounding box
- ChildScreenSpriteToDraw *child; ///< head of child list;
+ int first_child; ///< the first child to draw.
+ int last_child; ///< the last sprite to draw.
bool comparison_done; ///< Used during sprite sorting: true if sprite has been compared with all other sprites
};
-/* Quick hack to know how much memory to reserve when allocating from the spritelist
- * to prevent a buffer overflow. */
-#define LARGEST_SPRITELIST_STRUCT ParentSpriteToDraw
-assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(StringSpriteToDraw));
-assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(TileSpriteToDraw));
-assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ChildScreenSpriteToDraw));
-assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ParentSpriteToDraw));
-
/* Enumeration of multi-part foundations */
enum FoundationPart {
FOUNDATION_PART_NONE = 0xFF, ///< Neither foundation nor groundsprite drawn yet.
@@ -142,29 +129,32 @@
FOUNDATION_PART_END
};
+typedef SmallVector<TileSpriteToDraw, 64> TileSpriteToDrawVector;
+typedef SmallVector<StringSpriteToDraw, 4> StringSpriteToDrawVector;
+typedef SmallVector<ParentSpriteToDraw, 64> ParentSpriteToDrawVector;
+typedef SmallVector<ParentSpriteToDraw*, 64> ParentSpriteToSortVector;
+typedef SmallVector<ChildScreenSpriteToDraw, 16> ChildScreenSpriteToDrawVector;
+
struct ViewportDrawer {
DrawPixelInfo dpi;
- byte *spritelist_mem;
- const byte *eof_spritelist_mem;
-
- StringSpriteToDraw **last_string, *first_string;
- TileSpriteToDraw **last_tile, *first_tile;
-
- ChildScreenSpriteToDraw **last_child;
-
- ParentSpriteToDraw **parent_list;
- ParentSpriteToDraw * const *eof_parent_list;
+ StringSpriteToDrawVector string_sprites_to_draw;
+ TileSpriteToDrawVector tile_sprites_to_draw;
+ ParentSpriteToDrawVector parent_sprites_to_draw;
+ ParentSpriteToSortVector parent_sprites_to_sort;
+ ChildScreenSpriteToDrawVector child_screen_sprites_to_draw;
+
+ int *last_child;
byte combine_sprites;
- ParentSpriteToDraw *foundation[FOUNDATION_PART_END]; ///< Foundation sprites.
- FoundationPart foundation_part; ///< Currently active foundation for ground sprite drawing.
- ChildScreenSpriteToDraw **last_foundation_child[FOUNDATION_PART_END]; ///< Tail of ChildSprite list of the foundations.
- Point foundation_offset[FOUNDATION_PART_END]; ///< Pixeloffset for ground sprites on the foundations.
+ int foundation[FOUNDATION_PART_END]; ///< Foundation sprites (index into parent_sprites_to_draw).
+ FoundationPart foundation_part; ///< Currently active foundation for ground sprite drawing.
+ int *last_foundation_child[FOUNDATION_PART_END]; ///< Tail of ChildSprite list of the foundations. (index into child_screen_sprites_to_draw)
+ Point foundation_offset[FOUNDATION_PART_END]; ///< Pixeloffset for ground sprites on the foundations.
};
-static ViewportDrawer *_cur_vd;
+static ViewportDrawer _vd;
TileHighlightData _thd;
static TileInfo *_cur_ti;
@@ -486,28 +476,15 @@
*/
void DrawGroundSpriteAt(SpriteID image, SpriteID pal, int32 x, int32 y, byte z, const SubSprite *sub)
{
- ViewportDrawer *vd = _cur_vd;
- TileSpriteToDraw *ts;
-
assert((image & SPRITE_MASK) < MAX_SPRITES);
- if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
- DEBUG(sprite, 0, "Out of sprite memory");
- return;
- }
- ts = (TileSpriteToDraw*)vd->spritelist_mem;
-
- vd->spritelist_mem += sizeof(TileSpriteToDraw);
-
+ TileSpriteToDraw *ts = _vd.tile_sprites_to_draw.Append();
ts->image = image;
ts->pal = pal;
ts->sub = sub;
- ts->next = NULL;
ts->x = x;
ts->y = y;
ts->z = z;
- *vd->last_tile = ts;
- vd->last_tile = &ts->next;
}
/**
@@ -524,19 +501,18 @@
*/
static void AddChildSpriteToFoundation(SpriteID image, SpriteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y)
{
- ViewportDrawer *vd = _cur_vd;
assert(IsInsideMM(foundation_part, 0, FOUNDATION_PART_END));
- assert(vd->foundation[foundation_part] != NULL);
- Point offs = vd->foundation_offset[foundation_part];
+ assert(_vd.foundation[foundation_part] != -1);
+ Point offs = _vd.foundation_offset[foundation_part];
/* Change the active ChildSprite list to the one of the foundation */
- ChildScreenSpriteToDraw **old_child = vd->last_child;
- vd->last_child = vd->last_foundation_child[foundation_part];
+ int *old_child = _vd.last_child;
+ _vd.last_child = _vd.last_foundation_child[foundation_part];
AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub);
/* Switch back to last ChildSprite list */
- vd->last_child = old_child;
+ _vd.last_child = old_child;
}
/**
@@ -549,12 +525,11 @@
*/
void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub)
{
- ViewportDrawer *vd = _cur_vd;
/* Switch to first foundation part, if no foundation was drawn */
- if (vd->foundation_part == FOUNDATION_PART_NONE) vd->foundation_part = FOUNDATION_PART_NORMAL;
-
- if (vd->foundation[vd->foundation_part] != NULL) {
- AddChildSpriteToFoundation(image, pal, sub, vd->foundation_part, 0, 0);
+ if (_vd.foundation_part == FOUNDATION_PART_NONE) _vd.foundation_part = FOUNDATION_PART_NORMAL;
+
+ if (_vd.foundation[_vd.foundation_part] != -1) {
+ AddChildSpriteToFoundation(image, pal, sub, _vd.foundation_part, 0, 0);
} else {
DrawGroundSpriteAt(image, pal, _cur_ti->x, _cur_ti->y, _cur_ti->z, sub);
}
@@ -570,24 +545,23 @@
*/
void OffsetGroundSprite(int x, int y)
{
- ViewportDrawer *vd = _cur_vd;
/* Switch to next foundation part */
- switch (vd->foundation_part) {
+ switch (_vd.foundation_part) {
case FOUNDATION_PART_NONE:
- vd->foundation_part = FOUNDATION_PART_NORMAL;
+ _vd.foundation_part = FOUNDATION_PART_NORMAL;
break;
case FOUNDATION_PART_NORMAL:
- vd->foundation_part = FOUNDATION_PART_HALFTILE;
+ _vd.foundation_part = FOUNDATION_PART_HALFTILE;
break;
default: NOT_REACHED();
}
- /* vd->last_child == NULL if foundation sprite was clipped by the viewport bounds */
- if (vd->last_child != NULL) vd->foundation[vd->foundation_part] = vd->parent_list[-1];
-
- vd->foundation_offset[vd->foundation_part].x = x;
- vd->foundation_offset[vd->foundation_part].y = y;
- vd->last_foundation_child[vd->foundation_part] = vd->last_child;
+ /* _vd.last_child == NULL if foundation sprite was clipped by the viewport bounds */
+ if (_vd.last_child != NULL) _vd.foundation[_vd.foundation_part] = _vd.parent_sprites_to_draw.items - 1;
+
+ _vd.foundation_offset[_vd.foundation_part].x = x;
+ _vd.foundation_offset[_vd.foundation_part].y = y;
+ _vd.last_foundation_child[_vd.foundation_part] = _vd.last_child;
}
/**
@@ -603,17 +577,17 @@
*/
static void AddCombinedSprite(SpriteID image, SpriteID pal, int x, int y, byte z, const SubSprite *sub)
{
- const ViewportDrawer *vd = _cur_vd;
Point pt = RemapCoords(x, y, z);
const Sprite* spr = GetSprite(image & SPRITE_MASK);
- if (pt.x + spr->x_offs >= vd->dpi.left + vd->dpi.width ||
- pt.x + spr->x_offs + spr->width <= vd->dpi.left ||
- pt.y + spr->y_offs >= vd->dpi.top + vd->dpi.height ||
- pt.y + spr->y_offs + spr->height <= vd->dpi.top)
+ if (pt.x + spr->x_offs >= _vd.dpi.left + _vd.dpi.width ||
+ pt.x + spr->x_offs + spr->width <= _vd.dpi.left ||
+ pt.y + spr->y_offs >= _vd.dpi.top + _vd.dpi.height ||
+ pt.y + spr->y_offs + spr->height <= _vd.dpi.top)
return;
- AddChildSpriteScreen(image, pal, pt.x - vd->parent_list[-1]->left, pt.y - vd->parent_list[-1]->top, false, sub);
+ const ParentSpriteToDraw *pstd = _vd.parent_sprites_to_draw.End() - 1;
+ AddChildSpriteScreen(image, pal, pt.x - pstd->left, pt.y - pstd->top, false, sub);
}
/** Draw a (transparent) sprite at given coordinates with a given bounding box.
@@ -642,9 +616,6 @@
*/
void AddSortableSpriteToDraw(SpriteID image, SpriteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
{
- ViewportDrawer *vd = _cur_vd;
- ParentSpriteToDraw *ps;
- Point pt;
int32 left, right, top, bottom;
assert((image & SPRITE_MASK) < MAX_SPRITES);
@@ -655,45 +626,27 @@
pal = PALETTE_TO_TRANSPARENT;
}
- if (vd->combine_sprites == 2) {
+ if (_vd.combine_sprites == 2) {
AddCombinedSprite(image, pal, x, y, z, sub);
return;
}
- vd->last_child = NULL;
-
- if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
- DEBUG(sprite, 0, "Out of sprite memory");
- return;
- }
- ps = (ParentSpriteToDraw*)vd->spritelist_mem;
-
- if (vd->parent_list >= vd->eof_parent_list) {
- /* This can happen rarely, mostly when you zoom out completely
- * and have a lot of stuff that moves (and is added to the
- * sort-list, this function). To solve it, increase
- * parent_list somewhere below to a higher number.
- * This can not really hurt you, it just gives some black
- * spots on the screen ;) */
- DEBUG(sprite, 0, "Out of sprite memory (parent_list)");
- return;
- }
-
- pt = RemapCoords(x, y, z);
- ps->x = pt.x;
- ps->y = pt.y;
+ _vd.last_child = NULL;
+
+ Point pt = RemapCoords(x, y, z);
+ int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y;
/* Compute screen extents of sprite */
if (image == SPR_EMPTY_BOUNDING_BOX) {
- left = ps->left = RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x;
+ left = tmp_left = RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x;
right = RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1;
- top = ps->top = RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y;
+ top = tmp_top = RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y;
bottom = RemapCoords(x + w , y + h , z + bb_offset_z).y + 1;
} else {
const Sprite *spr = GetSprite(image & SPRITE_MASK);
- left = ps->left = (pt.x += spr->x_offs);
+ left = tmp_left = (pt.x += spr->x_offs);
right = (pt.x + spr->width );
- top = ps->top = (pt.y += spr->y_offs);
+ top = tmp_top = (pt.y += spr->y_offs);
bottom = (pt.y + spr->height);
}
@@ -706,14 +659,19 @@
}
/* Do not add the sprite to the viewport, if it is outside */
- if (left >= vd->dpi.left + vd->dpi.width ||
- right <= vd->dpi.left ||
- top >= vd->dpi.top + vd->dpi.height ||
- bottom <= vd->dpi.top) {
+ if (left >= _vd.dpi.left + _vd.dpi.width ||
+ right <= _vd.dpi.left ||
+ top >= _vd.dpi.top + _vd.dpi.height ||
+ bottom <= _vd.dpi.top) {
return;
}
- vd->spritelist_mem += sizeof(ParentSpriteToDraw);
+ ParentSpriteToDraw *ps = _vd.parent_sprites_to_draw.Append();
+ ps->x = tmp_x;
+ ps->y = tmp_y;
+
+ ps->left = tmp_left;
+ ps->top = tmp_top;
ps->image = image;
ps->pal = pal;
@@ -728,22 +686,22 @@
ps->zmax = z + max(bb_offset_z, dz) - 1;
ps->comparison_done = false;
- ps->child = NULL;
- vd->last_child = &ps->child;
-
- *vd->parent_list++ = ps;
-
- if (vd->combine_sprites == 1) vd->combine_sprites = 2;
+ ps->first_child = _vd.child_screen_sprites_to_draw.items;
+ ps->last_child = _vd.child_screen_sprites_to_draw.items;
+
+ _vd.last_child = &ps->last_child;
+
+ if (_vd.combine_sprites == 1) _vd.combine_sprites = 2;
}
void StartSpriteCombine()
{
- _cur_vd->combine_sprites = 1;
+ _vd.combine_sprites = 1;
}
void EndSpriteCombine()
{
- _cur_vd->combine_sprites = 0;
+ _vd.combine_sprites = 0;
}
/**
@@ -758,69 +716,41 @@
*/
void AddChildSpriteScreen(SpriteID image, SpriteID pal, int x, int y, bool transparent, const SubSprite *sub)
{
- ViewportDrawer *vd = _cur_vd;
- ChildScreenSpriteToDraw *cs;
-
assert((image & SPRITE_MASK) < MAX_SPRITES);
+ /* If the ParentSprite was clipped by the viewport bounds, do not draw the ChildSprites either */
+ if (_vd.last_child == NULL) return;
+
/* make the sprites transparent with the right palette */
if (transparent) {
SetBit(image, PALETTE_MODIFIER_TRANSPARENT);
pal = PALETTE_TO_TRANSPARENT;
}
- if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
- DEBUG(sprite, 0, "Out of sprite memory");
- return;
- }
- cs = (ChildScreenSpriteToDraw*)vd->spritelist_mem;
-
- /* If the ParentSprite was clipped by the viewport bounds, do not draw the ChildSprites either */
- if (vd->last_child == NULL) return;
-
- vd->spritelist_mem += sizeof(ChildScreenSpriteToDraw);
-
/* Append the sprite to the active ChildSprite list.
* If the active ParentSprite is a foundation, update last_foundation_child as well. */
- *vd->last_child = cs;
- if (vd->last_foundation_child[0] == vd->last_child) vd->last_foundation_child[0] = &cs->next;
- if (vd->last_foundation_child[1] == vd->last_child) vd->last_foundation_child[1] = &cs->next;
- vd->last_child = &cs->next;
-
+ ChildScreenSpriteToDraw *cs = _vd.child_screen_sprites_to_draw.Append();
cs->image = image;
cs->pal = pal;
cs->sub = sub;
cs->x = x;
cs->y = y;
cs->next = NULL;
+
+ *_vd.last_child = _vd.child_screen_sprites_to_draw.items;
}
/* Returns a StringSpriteToDraw */
-void *AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2)
+void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, uint16 color, uint16 width)
{
- ViewportDrawer *vd = _cur_vd;
- StringSpriteToDraw *ss;
-
- if (vd->spritelist_mem >= vd->eof_spritelist_mem) {
- DEBUG(sprite, 0, "Out of sprite memory");
- return NULL;
- }
- ss = (StringSpriteToDraw*)vd->spritelist_mem;
-
- vd->spritelist_mem += sizeof(StringSpriteToDraw);
-
+ StringSpriteToDraw *ss = _vd.string_sprites_to_draw.Append();
ss->string = string;
- ss->next = NULL;
ss->x = x;
ss->y = y;
ss->params[0] = params_1;
ss->params[1] = params_2;
- ss->width = 0;
-
- *vd->last_string = ss;
- vd->last_string = &ss->next;
-
- return ss;
+ ss->width = width;
+ ss->color = color;
}
@@ -838,7 +768,7 @@
static void DrawSelectionSprite(SpriteID image, SpriteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part)
{
/* FIXME: This is not totally valid for some autorail highlights, that extent over the edges of the tile. */
- if (_cur_vd->foundation[foundation_part] == NULL) {
+ if (_vd.foundation[foundation_part] == -1) {
/* draw on real ground */
DrawGroundSpriteAt(image, pal, ti->x, ti->y, ti->z + z_offset);
} else {
@@ -1036,7 +966,6 @@
static void ViewportAddLandscape()
{
- ViewportDrawer *vd = _cur_vd;
int x, y, width, height;
TileInfo ti;
bool direction;
@@ -1044,14 +973,14 @@
_cur_ti = &ti;
/* Transform into tile coordinates and round to closest full tile */
- x = ((vd->dpi.top >> 1) - (vd->dpi.left >> 2)) & ~0xF;
- y = ((vd->dpi.top >> 1) + (vd->dpi.left >> 2) - 0x10) & ~0xF;
+ x = ((_vd.dpi.top >> 1) - (_vd.dpi.left >> 2)) & ~0xF;
+ y = ((_vd.dpi.top >> 1) + (_vd.dpi.left >> 2) - 0x10) & ~0xF;
/* determine size of area */
{
Point pt = RemapCoords(x, y, 241);
- width = (vd->dpi.left + vd->dpi.width - pt.x + 95) >> 6;
- height = (vd->dpi.top + vd->dpi.height - pt.y) >> 5 << 1;
+ width = (_vd.dpi.left + _vd.dpi.width - pt.x + 95) >> 6;
+ height = (_vd.dpi.top + _vd.dpi.height - pt.y) >> 5 << 1;
}
assert(width > 0);
@@ -1086,11 +1015,11 @@
y_cur += 0x10;
x_cur -= 0x10;
- vd->foundation_part = FOUNDATION_PART_NONE;
- vd->foundation[0] = NULL;
- vd->foundation[1] = NULL;
- vd->last_foundation_child[0] = NULL;
- vd->last_foundation_child[1] = NULL;
+ _vd.foundation_part = FOUNDATION_PART_NONE;
+ _vd.foundation[0] = -1;
+ _vd.foundation[1] = -1;
+ _vd.last_foundation_child[0] = NULL;
+ _vd.last_foundation_child[1] = NULL;
_tile_type_procs[tt]->draw_tile_proc(&ti);
DrawTileSelection(&ti);
@@ -1171,13 +1100,7 @@
static void AddStation(const Station *st, StringID str, uint16 width)
{
- StringSpriteToDraw *sstd;
-
- sstd = (StringSpriteToDraw*)AddStringToDraw(st->sign.left + 1, st->sign.top + 1, str, st->index, st->facilities);
- if (sstd != NULL) {
- sstd->color = (st->owner == OWNER_NONE || st->facilities == 0) ? 0xE : _player_colors[st->owner];
- sstd->width = width;
- }
+ AddStringToDraw(st->sign.left + 1, st->sign.top + 1, str, st->index, st->facilities, (st->owner == OWNER_NONE || st->facilities == 0) ? 0xE : _player_colors[st->owner], width);
}
@@ -1241,13 +1164,7 @@
static void AddSign(const Sign *si, StringID str, uint16 width)
{
- StringSpriteToDraw *sstd;
-
- sstd = (StringSpriteToDraw*)AddStringToDraw(si->sign.left + 1, si->sign.top + 1, str, si->index, 0);
- if (sstd != NULL) {
- sstd->color = (si->owner == OWNER_NONE) ? 14 : _player_colors[si->owner];
- sstd->width = width;
- }
+ AddStringToDraw(si->sign.left + 1, si->sign.top + 1, str, si->index, 0, (si->owner == OWNER_NONE) ? 14 : _player_colors[si->owner], width);
}
@@ -1311,13 +1228,7 @@
static void AddWaypoint(const Waypoint *wp, StringID str, uint16 width)
{
- StringSpriteToDraw *sstd;
-
- sstd = (StringSpriteToDraw*)AddStringToDraw(wp->sign.left + 1, wp->sign.top + 1, str, wp->index, 0);
- if (sstd != NULL) {
- sstd->color = (wp->deleted ? 0xE : 11);
- sstd->width = width;
- }
+ AddStringToDraw(wp->sign.left + 1, wp->sign.top + 1, str, wp->index, 0, (wp->deleted ? 0xE : 11), width);
}
@@ -1398,84 +1309,84 @@
}
-static void ViewportDrawTileSprites(TileSpriteToDraw *ts)
+static void ViewportDrawTileSprites(const TileSpriteToDrawVector *tstdv)
{
- do {
+ const TileSpriteToDraw *tsend = tstdv->End();
+ for (const TileSpriteToDraw *ts = tstdv->Begin(); ts != tsend; ++ts) {
Point pt = RemapCoords(ts->x, ts->y, ts->z);
DrawSprite(ts->image, ts->pal, pt.x, pt.y, ts->sub);
- ts = ts->next;
- } while (ts != NULL);
+ }
}
-static void ViewportSortParentSprites(ParentSpriteToDraw *psd[])
+static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv)
{
- while (*psd != NULL) {
- ParentSpriteToDraw* ps = *psd;
-
- if (!ps->comparison_done) {
- ParentSpriteToDraw** psd2 = psd;
-
- ps->comparison_done = true;
-
- while (*++psd2 != NULL) {
- ParentSpriteToDraw* ps2 = *psd2;
- ParentSpriteToDraw** psd3;
-
- if (ps2->comparison_done) continue;
-
- /* Decide which comparator to use, based on whether the bounding
- * boxes overlap
+ ParentSpriteToDraw **psdvend = psdv->End();
+ ParentSpriteToDraw **psd = psdv->Begin();
+ while (psd != psdvend) {
+ ParentSpriteToDraw *ps = *psd;
+
+ if (ps->comparison_done) {
+ psd++;
+ continue;
+ }
+
+ ps->comparison_done = true;
+
+ for (ParentSpriteToDraw **psd2 = psd + 1; psd2 != psdvend; psd2++) {
+ ParentSpriteToDraw *ps2 = *psd2;
+
+ if (ps2->comparison_done) continue;
+
+ /* Decide which comparator to use, based on whether the bounding
+ * boxes overlap
+ */
+ if (ps->xmax >= ps2->xmin && ps->xmin <= ps2->xmax && // overlap in X?
+ ps->ymax >= ps2->ymin && ps->ymin <= ps2->ymax && // overlap in Y?
+ ps->zmax >= ps2->zmin && ps->zmin <= ps2->zmax) { // overlap in Z?
+ /* Use X+Y+Z as the sorting order, so sprites closer to the bottom of
+ * the screen and with higher Z elevation, are drawn in front.
+ * Here X,Y,Z are the coordinates of the "center of mass" of the sprite,
+ * i.e. X=(left+right)/2, etc.
+ * However, since we only care about order, don't actually divide / 2
*/
- if (ps->xmax >= ps2->xmin && ps->xmin <= ps2->xmax && // overlap in X?
- ps->ymax >= ps2->ymin && ps->ymin <= ps2->ymax && // overlap in Y?
- ps->zmax >= ps2->zmin && ps->zmin <= ps2->zmax) { // overlap in Z?
- /* Use X+Y+Z as the sorting order, so sprites closer to the bottom of
- * the screen and with higher Z elevation, are drawn in front.
- * Here X,Y,Z are the coordinates of the "center of mass" of the sprite,
- * i.e. X=(left+right)/2, etc.
- * However, since we only care about order, don't actually divide / 2
- */
- if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <=
- ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) {
- continue;
- }
- } else {
- /* We only change the order, if it is definite.
- * I.e. every single order of X, Y, Z says ps2 is behind ps or they overlap.
- * That is: If one partial order says ps behind ps2, do not change the order.
- */
- if (ps->xmax < ps2->xmin ||
- ps->ymax < ps2->ymin ||
- ps->zmax < ps2->zmin) {
- continue;
- }
+ if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <=
+ ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) {
+ continue;
}
-
- /* Swap the two sprites ps and ps2 using bubble-sort algorithm. */
- psd3 = psd;
- do {
- ParentSpriteToDraw* temp = *psd3;
- *psd3 = ps2;
- ps2 = temp;
-
- psd3++;
- } while (psd3 <= psd2);
+ } else {
+ /* We only change the order, if it is definite.
+ * I.e. every single order of X, Y, Z says ps2 is behind ps or they overlap.
+ * That is: If one partial order says ps behind ps2, do not change the order.
+ */
+ if (ps->xmax < ps2->xmin ||
+ ps->ymax < ps2->ymin ||
+ ps->zmax < ps2->zmin) {
+ continue;
+ }
}
- } else {
- psd++;
+
+ /* Swap the two sprites ps and ps2 using bubble-sort algorithm. */
+ ParentSpriteToDraw **psd3 = psd;
+ do {
+ ParentSpriteToDraw *temp = *psd3;
+ *psd3 = ps2;
+ ps2 = temp;
+
+ psd3++;
+ } while (psd3 <= psd2);
}
}
}
-static void ViewportDrawParentSprites(ParentSpriteToDraw *psd[])
+static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv)
{
- for (; *psd != NULL; psd++) {
- const ParentSpriteToDraw* ps = *psd;
- const ChildScreenSpriteToDraw* cs;
-
+ const ParentSpriteToDraw * const *psd_end = psd->End();
+ for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) {
+ const ParentSpriteToDraw *ps = *it;
if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSprite(ps->image, ps->pal, ps->x, ps->y, ps->sub);
- for (cs = ps->child; cs != NULL; cs = cs->next) {
+ const ChildScreenSpriteToDraw *last = csstdv->Get(ps->last_child);
+ for (const ChildScreenSpriteToDraw *cs = csstdv->Get(ps->first_child); cs != last; cs++) {
DrawSprite(cs->image, cs->pal, ps->left + cs->x, ps->top + cs->y, cs->sub);
}
}
@@ -1485,10 +1396,11 @@
* Draws the bounding boxes of all ParentSprites
* @param psd Array of ParentSprites
*/
-static void ViewportDrawBoundingBoxes(ParentSpriteToDraw *psd[])
+static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd)
{
- for (; *psd != NULL; psd++) {
- const ParentSpriteToDraw* ps = *psd;
+ const ParentSpriteToDraw * const *psd_end = psd->End();
+ for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) {
+ const ParentSpriteToDraw *ps = *it;
Point pt1 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmax + 1); // top front corner
Point pt2 = RemapCoords(ps->xmin , ps->ymax + 1, ps->zmax + 1); // top left corner
Point pt3 = RemapCoords(ps->xmax + 1, ps->ymin , ps->zmax + 1); // top right corner
@@ -1501,7 +1413,7 @@
}
}
-static void ViewportDrawStrings(DrawPixelInfo *dpi, const StringSpriteToDraw *ss)
+static void ViewportDrawStrings(DrawPixelInfo *dpi, const StringSpriteToDrawVector *sstdv)
{
DrawPixelInfo dp;
ZoomLevel zoom;
@@ -1517,15 +1429,13 @@
dp.width = UnScaleByZoom(dp.width, zoom);
dp.height = UnScaleByZoom(dp.height, zoom);
- do {
+ const StringSpriteToDraw *ssend = sstdv->End();
+ for (const StringSpriteToDraw *ss = sstdv->Begin(); ss != ssend; ++ss) {
uint16 colour;
if (ss->width != 0) {
/* Do not draw signs nor station names if they are set invisible */
- if (IsInvisibilitySet(TO_SIGNS) && ss->string != STR_2806) {
- ss = ss->next;
- continue;
- }
+ if (IsInvisibilitySet(TO_SIGNS) && ss->string != STR_2806) continue;
int x = UnScaleByZoom(ss->x, zoom) - 1;
int y = UnScaleByZoom(ss->y, zoom) - 1;
@@ -1564,78 +1474,61 @@
UnScaleByZoom(ss->x, zoom), UnScaleByZoom(ss->y, zoom) - (ss->width & 0x8000 ? 2 : 0),
ss->string, colour
);
-
- ss = ss->next;
- } while (ss != NULL);
+ }
}
void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom)
{
- ViewportDrawer vd;
- int mask;
- int x;
- int y;
- DrawPixelInfo *old_dpi;
-
- SmallStackSafeStackAlloc<byte, VIEWPORT_DRAW_MEM> mem;
- SmallStackSafeStackAlloc<ParentSpriteToDraw*, PARENT_LIST_SIZE> parent_list;
-
- _cur_vd = &vd;
-
- old_dpi = _cur_dpi;
- _cur_dpi = &vd.dpi;
-
- vd.dpi.zoom = vp->zoom;
- mask = ScaleByZoom(-1, vp->zoom);
-
- vd.combine_sprites = 0;
-
- vd.dpi.width = (right - left) & mask;
- vd.dpi.height = (bottom - top) & mask;
- vd.dpi.left = left & mask;
- vd.dpi.top = top & mask;
- vd.dpi.pitch = old_dpi->pitch;
-
- x = UnScaleByZoom(vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left;
- y = UnScaleByZoom(vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top;
-
- vd.dpi.dst_ptr = BlitterFactoryBase::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top);
-
- vd.parent_list = parent_list;
- vd.eof_parent_list = parent_list.EndOf();
- vd.spritelist_mem = mem;
- vd.eof_spritelist_mem = mem.EndOf() - sizeof(LARGEST_SPRITELIST_STRUCT);
- vd.last_string = &vd.first_string;
- vd.first_string = NULL;
- vd.last_tile = &vd.first_tile;
- vd.first_tile = NULL;
+ DrawPixelInfo *old_dpi = _cur_dpi;
+ _cur_dpi = &_vd.dpi;
+
+ _vd.dpi.zoom = vp->zoom;
+ int mask = ScaleByZoom(-1, vp->zoom);
+
+ _vd.combine_sprites = 0;
+
+ _vd.dpi.width = (right - left) & mask;
+ _vd.dpi.height = (bottom - top) & mask;
+ _vd.dpi.left = left & mask;
+ _vd.dpi.top = top & mask;
+ _vd.dpi.pitch = old_dpi->pitch;
+ _vd.last_child = NULL;
+
+ int x = UnScaleByZoom(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left;
+ int y = UnScaleByZoom(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top;
+
+ _vd.dpi.dst_ptr = BlitterFactoryBase::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top);
ViewportAddLandscape();
- ViewportAddVehicles(&vd.dpi);
- DrawTextEffects(&vd.dpi);
-
- ViewportAddTownNames(&vd.dpi);
- ViewportAddStationNames(&vd.dpi);
- ViewportAddSigns(&vd.dpi);
- ViewportAddWaypoints(&vd.dpi);
-
- /* This assert should never happen (because the length of the parent_list
- * is checked) */
- assert(vd.parent_list <= endof(parent_list));
-
- if (vd.first_tile != NULL) ViewportDrawTileSprites(vd.first_tile);
-
- /* null terminate parent sprite list */
- *vd.parent_list = NULL;
-
- ViewportSortParentSprites(parent_list);
- ViewportDrawParentSprites(parent_list);
-
- if (_draw_bounding_boxes) ViewportDrawBoundingBoxes(parent_list);
-
- if (vd.first_string != NULL) ViewportDrawStrings(&vd.dpi, vd.first_string);
+ ViewportAddVehicles(&_vd.dpi);
+ DrawTextEffects(&_vd.dpi);
+
+ ViewportAddTownNames(&_vd.dpi);
+ ViewportAddStationNames(&_vd.dpi);
+ ViewportAddSigns(&_vd.dpi);
+ ViewportAddWaypoints(&_vd.dpi);
+
+ if (_vd.tile_sprites_to_draw.items != 0) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw);
+
+ ParentSpriteToDraw *psd_end = _vd.parent_sprites_to_draw.End();
+ for (ParentSpriteToDraw *it = _vd.parent_sprites_to_draw.Begin(); it != psd_end; it++) {
+ *_vd.parent_sprites_to_sort.Append() = it;
+ }
+
+ ViewportSortParentSprites(&_vd.parent_sprites_to_sort);
+ ViewportDrawParentSprites(&_vd.parent_sprites_to_sort, &_vd.child_screen_sprites_to_draw);
+
+ if (_draw_bounding_boxes) ViewportDrawBoundingBoxes(&_vd.parent_sprites_to_sort);
+
+ if (_vd.string_sprites_to_draw.items != 0) ViewportDrawStrings(&_vd.dpi, &_vd.string_sprites_to_draw);
_cur_dpi = old_dpi;
+
+ _vd.string_sprites_to_draw.items = 0;
+ _vd.tile_sprites_to_draw.items = 0;
+ _vd.parent_sprites_to_draw.items = 0;
+ _vd.parent_sprites_to_sort.items = 0;
+ _vd.child_screen_sprites_to_draw.items = 0;
}
/** Make sure we don't draw a too big area at a time.
--- a/src/viewport_func.h Wed Apr 16 22:16:04 2008 +0000
+++ b/src/viewport_func.h Wed Apr 16 22:34:14 2008 +0000
@@ -34,7 +34,7 @@
void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub = NULL);
void DrawGroundSpriteAt(SpriteID image, SpriteID pal, int32 x, int32 y, byte z, const SubSprite *sub = NULL);
void AddSortableSpriteToDraw(SpriteID image, SpriteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = NULL);
-void *AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2);
+void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, uint16 color = 0, uint16 width = 0);
void AddChildSpriteScreen(SpriteID image, SpriteID pal, int x, int y, bool transparent = false, const SubSprite *sub = NULL);
--- a/src/window.cpp Wed Apr 16 22:16:04 2008 +0000
+++ b/src/window.cpp Wed Apr 16 22:34:14 2008 +0000
@@ -2316,7 +2316,7 @@
const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0);
if (wt != NULL) {
- if (top < wt->height) top = wt->height;
+ if (top < wt->height && wt->left < (w->left + w->width) && (wt->left + wt->width) > w->left) top = wt->height;
if (top >= newh) top = newh - 1;
} else {
if (top < 0) top = 0;