Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/extern
diff options
context:
space:
mode:
Diffstat (limited to 'extern')
-rw-r--r--extern/CMakeLists.txt4
-rw-r--r--extern/audaspace/CMakeLists.txt2
-rw-r--r--extern/audaspace/include/devices/SoftwareDevice.h1
-rw-r--r--extern/audaspace/include/devices/ThreadedDevice.h95
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp1
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp62
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h19
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h14
-rw-r--r--extern/audaspace/plugins/wasapi/WASAPIDevice.cpp169
-rw-r--r--extern/audaspace/plugins/wasapi/WASAPIDevice.h29
-rw-r--r--extern/audaspace/src/devices/SoftwareDevice.cpp6
-rw-r--r--extern/audaspace/src/devices/ThreadedDevice.cpp65
-rw-r--r--extern/mantaflow/preprocessed/fileio/iovdb.cpp13
-rw-r--r--extern/mantaflow/preprocessed/fluidsolver.h1
-rw-r--r--extern/mantaflow/preprocessed/general.h2
-rw-r--r--extern/mantaflow/preprocessed/gitinfo.h2
-rw-r--r--extern/mantaflow/preprocessed/grid.h1
-rw-r--r--extern/mantaflow/preprocessed/grid4d.h2
-rw-r--r--extern/mantaflow/preprocessed/levelset.h1
-rw-r--r--extern/mantaflow/preprocessed/mesh.h3
-rw-r--r--extern/mantaflow/preprocessed/movingobs.h1
-rw-r--r--extern/mantaflow/preprocessed/noisefield.h1
-rw-r--r--extern/mantaflow/preprocessed/particle.h6
-rw-r--r--extern/mantaflow/preprocessed/plugin/meshplugins.cpp8
-rw-r--r--extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp7
-rw-r--r--extern/mantaflow/preprocessed/shapes.h6
-rw-r--r--extern/mantaflow/preprocessed/turbulencepart.h1
-rw-r--r--extern/mantaflow/preprocessed/vortexpart.h1
-rw-r--r--extern/mantaflow/preprocessed/vortexsheet.h1
-rw-r--r--extern/smaa_areatex/CMakeLists.txt26
-rw-r--r--extern/smaa_areatex/README.blender5
-rw-r--r--extern/smaa_areatex/smaa_areatex.cpp1208
32 files changed, 1541 insertions, 222 deletions
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 235c2fa931a..824b2fb0e9c 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -109,3 +109,7 @@ endif()
if(WITH_MOD_FLUID)
add_subdirectory(mantaflow)
endif()
+
+if (WITH_COMPOSITOR)
+ add_subdirectory(smaa_areatex)
+endif()
diff --git a/extern/audaspace/CMakeLists.txt b/extern/audaspace/CMakeLists.txt
index fe1bf5dc742..1599c03cbad 100644
--- a/extern/audaspace/CMakeLists.txt
+++ b/extern/audaspace/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SRC
src/devices/NULLDevice.cpp
src/devices/ReadDevice.cpp
src/devices/SoftwareDevice.cpp
+ src/devices/ThreadedDevice.cpp
src/Exception.cpp
src/file/File.cpp
src/file/FileManager.cpp
@@ -148,6 +149,7 @@ set(PUBLIC_HDR
include/devices/NULLDevice.h
include/devices/ReadDevice.h
include/devices/SoftwareDevice.h
+ include/devices/ThreadedDevice.h
include/Exception.h
include/file/File.h
include/file/FileManager.h
diff --git a/extern/audaspace/include/devices/SoftwareDevice.h b/extern/audaspace/include/devices/SoftwareDevice.h
index a350550048b..209be9941b1 100644
--- a/extern/audaspace/include/devices/SoftwareDevice.h
+++ b/extern/audaspace/include/devices/SoftwareDevice.h
@@ -255,6 +255,7 @@ protected:
/**
* This function tells the device, to start or pause playback.
* \param playing True if device should playback.
+ * \note This method is only called when the device is locked.
*/
virtual void playing(bool playing)=0;
diff --git a/extern/audaspace/include/devices/ThreadedDevice.h b/extern/audaspace/include/devices/ThreadedDevice.h
new file mode 100644
index 00000000000..36c2e68e36f
--- /dev/null
+++ b/extern/audaspace/include/devices/ThreadedDevice.h
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+/**
+ * @file ThreadedDevice.h
+ * @ingroup plugin
+ * The ThreadedDevice class.
+ */
+
+#include "devices/SoftwareDevice.h"
+
+#include <thread>
+
+AUD_NAMESPACE_BEGIN
+
+/**
+ * This device extends the SoftwareDevice with code for running mixing in a separate thread.
+ */
+class AUD_PLUGIN_API ThreadedDevice : public SoftwareDevice
+{
+private:
+ /**
+ * Whether there is currently playback.
+ */
+ bool m_playing;
+
+ /**
+ * Whether the current playback should stop.
+ */
+ bool m_stop;
+
+ /**
+ * The streaming thread.
+ */
+ std::thread m_thread;
+
+ /**
+ * Starts the streaming thread.
+ */
+ AUD_LOCAL void start();
+
+ /**
+ * Streaming thread main function.
+ */
+ AUD_LOCAL virtual void runMixingThread()=0;
+
+ // delete copy constructor and operator=
+ ThreadedDevice(const ThreadedDevice&) = delete;
+ ThreadedDevice& operator=(const ThreadedDevice&) = delete;
+
+protected:
+ virtual void playing(bool playing);
+
+ /**
+ * Empty default constructor. To setup the device call the function create()
+ * and to uninitialize call destroy().
+ */
+ ThreadedDevice();
+
+ /**
+ * Indicates that the mixing thread should be stopped.
+ * \return Whether the mixing thread should be stopping.
+ * \warning For thread safety, the device needs to be locked, when this method is called.
+ */
+ inline bool shouldStop() { return m_stop; }
+
+ /**
+ * This method needs to be called when the mixing thread is stopping.
+ * \warning For thread safety, the device needs to be locked, when this method is called.
+ */
+ inline void doStop() { m_stop = m_playing = false; }
+
+ /**
+ * Stops all playback and notifies the mixing thread to stop.
+ * \warning The device has to be unlocked to not run into a deadlock.
+ */
+ void stopMixingThread();
+};
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp
index 2cd3261bd20..10517d1d596 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp
@@ -75,6 +75,7 @@ void FFMPEGWriter::encode()
m_frame->nb_samples = m_input_samples;
m_frame->format = m_codecCtx->sample_fmt;
m_frame->channel_layout = m_codecCtx->channel_layout;
+ m_frame->channels = m_specs.channels;
if(avcodec_fill_audio_frame(m_frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0)
AUD_THROW(FileException, "File couldn't be written, filling the audio frame failed with ffmpeg.");
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
index 0a50d5db2c7..3ffe97661d8 100644
--- a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
@@ -27,9 +27,9 @@ void PulseAudioDevice::PulseAudio_state_callback(pa_context *context, void *data
{
PulseAudioDevice* device = (PulseAudioDevice*)data;
- device->m_state = AUD_pa_context_get_state(context);
+ std::lock_guard<ILockable> lock(*device);
- AUD_pa_threaded_mainloop_signal(device->m_mainloop, 0);
+ device->m_state = AUD_pa_context_get_state(context);
}
void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t num_bytes, void *data)
@@ -68,29 +68,40 @@ void PulseAudioDevice::PulseAudio_underflow(pa_stream *stream, void *data)
}
}
-void PulseAudioDevice::playing(bool playing)
+void PulseAudioDevice::runMixingThread()
{
- m_playback = playing;
+ for(;;)
+ {
+ {
+ std::lock_guard<ILockable> lock(*this);
+
+ if(shouldStop())
+ {
+ AUD_pa_stream_cork(m_stream, 1, nullptr, nullptr);
+ doStop();
+ return;
+ }
+ }
+
+ if(AUD_pa_stream_is_corked(m_stream))
+ AUD_pa_stream_cork(m_stream, 0, nullptr, nullptr);
- AUD_pa_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr);
+ AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
+ }
}
PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buffersize) :
- m_playback(false),
m_state(PA_CONTEXT_UNCONNECTED),
m_buffersize(buffersize),
m_underflows(0)
{
- m_mainloop = AUD_pa_threaded_mainloop_new();
+ m_mainloop = AUD_pa_mainloop_new();
- AUD_pa_threaded_mainloop_lock(m_mainloop);
-
- m_context = AUD_pa_context_new(AUD_pa_threaded_mainloop_get_api(m_mainloop), name.c_str());
+ m_context = AUD_pa_context_new(AUD_pa_mainloop_get_api(m_mainloop), name.c_str());
if(!m_context)
{
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
}
@@ -99,26 +110,21 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
AUD_pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
- AUD_pa_threaded_mainloop_start(m_mainloop);
-
while(m_state != PA_CONTEXT_READY)
{
switch(m_state)
{
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
- AUD_pa_threaded_mainloop_stop(m_mainloop);
-
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
break;
default:
- AUD_pa_threaded_mainloop_wait(m_mainloop);
+ AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
break;
}
}
@@ -166,13 +172,10 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
if(!m_stream)
{
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
- AUD_pa_threaded_mainloop_stop(m_mainloop);
-
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not create PulseAudio stream.");
}
@@ -188,32 +191,27 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
buffer_attr.prebuf = -1U;
buffer_attr.tlength = buffersize;
- if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
+ if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
{
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
- AUD_pa_threaded_mainloop_stop(m_mainloop);
-
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect PulseAudio stream.");
}
- AUD_pa_threaded_mainloop_unlock(m_mainloop);
-
create();
}
PulseAudioDevice::~PulseAudioDevice()
{
- AUD_pa_threaded_mainloop_stop(m_mainloop);
+ stopMixingThread();
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
- AUD_pa_threaded_mainloop_free(m_mainloop);
+ AUD_pa_mainloop_free(m_mainloop);
destroy();
}
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h
index 9efae5128b1..be34cc9032b 100644
--- a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h
@@ -26,7 +26,7 @@
* The PulseAudioDevice class.
*/
-#include "devices/SoftwareDevice.h"
+#include "devices/ThreadedDevice.h"
#include <pulse/pulseaudio.h>
@@ -35,15 +35,10 @@ AUD_NAMESPACE_BEGIN
/**
* This device plays back through PulseAudio, the simple direct media layer.
*/
-class AUD_PLUGIN_API PulseAudioDevice : public SoftwareDevice
+class AUD_PLUGIN_API PulseAudioDevice : public ThreadedDevice
{
private:
- /**
- * Whether there is currently playback.
- */
- volatile bool m_playback;
-
- pa_threaded_mainloop* m_mainloop;
+ pa_mainloop* m_mainloop;
pa_context* m_context;
pa_stream* m_stream;
pa_context_state_t m_state;
@@ -74,13 +69,15 @@ private:
*/
AUD_LOCAL static void PulseAudio_underflow(pa_stream* stream, void* data);
+ /**
+ * Streaming thread main function.
+ */
+ AUD_LOCAL void runMixingThread();
+
// delete copy constructor and operator=
PulseAudioDevice(const PulseAudioDevice&) = delete;
PulseAudioDevice& operator=(const PulseAudioDevice&) = delete;
-protected:
- virtual void playing(bool playing);
-
public:
/**
* Opens the PulseAudio audio device for playback.
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h b/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h
index 9cefbc0c7e2..4b9e1ffea2b 100644
--- a/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h
@@ -24,18 +24,14 @@ PULSEAUDIO_SYMBOL(pa_context_unref);
PULSEAUDIO_SYMBOL(pa_stream_begin_write);
PULSEAUDIO_SYMBOL(pa_stream_connect_playback);
PULSEAUDIO_SYMBOL(pa_stream_cork);
+PULSEAUDIO_SYMBOL(pa_stream_is_corked);
PULSEAUDIO_SYMBOL(pa_stream_new);
PULSEAUDIO_SYMBOL(pa_stream_set_buffer_attr);
PULSEAUDIO_SYMBOL(pa_stream_set_underflow_callback);
PULSEAUDIO_SYMBOL(pa_stream_set_write_callback);
PULSEAUDIO_SYMBOL(pa_stream_write);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_free);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_get_api);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_lock);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_new);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_signal);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_start);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_stop);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_unlock);
-PULSEAUDIO_SYMBOL(pa_threaded_mainloop_wait);
+PULSEAUDIO_SYMBOL(pa_mainloop_free);
+PULSEAUDIO_SYMBOL(pa_mainloop_get_api);
+PULSEAUDIO_SYMBOL(pa_mainloop_new);
+PULSEAUDIO_SYMBOL(pa_mainloop_iterate);
diff --git a/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp b/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
index 4f213dc8468..b4632ebb83e 100644
--- a/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
+++ b/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp
@@ -31,159 +31,83 @@ template <class T> void SafeRelease(T **ppT)
}
}
-void WASAPIDevice::start()
-{
- lock();
-
- // thread is still running, we can abort stopping it
- if(m_stop)
- m_stop = false;
- // thread is not running, let's start it
- else if(!m_playing)
- {
- if(m_thread.joinable())
- m_thread.join();
-
- m_playing = true;
-
- m_thread = std::thread(&WASAPIDevice::updateStream, this);
- }
-
- unlock();
-}
-
-void WASAPIDevice::updateStream()
+void WASAPIDevice::runMixingThread()
{
UINT32 buffer_size;
+ UINT32 padding;
+ UINT32 length;
data_t* buffer;
- lock();
+ IAudioRenderClient* render_client = nullptr;
- if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
{
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ std::lock_guard<ILockable> lock(*this);
- IAudioRenderClient* render_client = nullptr;
- const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
+ const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
- if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
- {
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
+ goto init_error;
- UINT32 padding;
+ if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
+ goto init_error;
- if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
- {
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
+ goto init_error;
- UINT32 length = buffer_size - padding;
+ length = buffer_size - padding;
- if(FAILED(render_client->GetBuffer(length, &buffer)))
- {
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ if(FAILED(render_client->GetBuffer(length, &buffer)))
+ goto init_error;
- mix((data_t*)buffer, length);
+ mix((data_t*)buffer, length);
- if(FAILED(render_client->ReleaseBuffer(length, 0)))
- {
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
+ if(FAILED(render_client->ReleaseBuffer(length, 0)))
+ {
+ init_error:
+ SafeRelease(&render_client);
+ doStop();
+ return;
+ }
}
- unlock();
-
m_audio_client->Start();
auto sleepDuration = std::chrono::milliseconds(buffer_size * 1000 / int(m_specs.rate) / 2);
for(;;)
{
- lock();
-
- if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
- m_audio_client->Stop();
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ std::lock_guard<ILockable> lock(*this);
- length = buffer_size - padding;
+ if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
+ goto stop_thread;
- if(FAILED(render_client->GetBuffer(length, &buffer)))
- {
- m_audio_client->Stop();
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ length = buffer_size - padding;
- mix((data_t*)buffer, length);
+ if(FAILED(render_client->GetBuffer(length, &buffer)))
+ goto stop_thread;
- if(FAILED(render_client->ReleaseBuffer(length, 0)))
- {
- m_audio_client->Stop();
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ mix((data_t*)buffer, length);
- // stop thread
- if(m_stop)
- {
- m_audio_client->Stop();
- SafeRelease(&render_client);
- m_playing = false;
- m_stop = false;
- unlock();
- return;
- }
+ if(FAILED(render_client->ReleaseBuffer(length, 0)))
+ goto stop_thread;
- unlock();
+ // stop thread
+ if(shouldStop())
+ {
+ stop_thread:
+ m_audio_client->Stop();
+ SafeRelease(&render_client);
+ doStop();
+ return;
+ }
+ }
std::this_thread::sleep_for(sleepDuration);
}
}
-void WASAPIDevice::playing(bool playing)
-{
- if((!m_playing || m_stop) && playing)
- start();
- else
- m_stop = true;
-}
-
WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
- m_playing(false),
- m_stop(false),
-
m_imm_device_enumerator(nullptr),
m_imm_device(nullptr),
m_audio_client(nullptr),
@@ -361,14 +285,7 @@ WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
WASAPIDevice::~WASAPIDevice()
{
- lock();
-
- stopAll();
-
- unlock();
-
- if(m_thread.joinable())
- m_thread.join();
+ stopMixingThread();
SafeRelease(&m_audio_client);
SafeRelease(&m_imm_device);
diff --git a/extern/audaspace/plugins/wasapi/WASAPIDevice.h b/extern/audaspace/plugins/wasapi/WASAPIDevice.h
index ae25a09c432..375f03bd255 100644
--- a/extern/audaspace/plugins/wasapi/WASAPIDevice.h
+++ b/extern/audaspace/plugins/wasapi/WASAPIDevice.h
@@ -26,7 +26,7 @@
* The WASAPIDevice class.
*/
-#include "devices/SoftwareDevice.h"
+#include "devices/ThreadedDevice.h"
#include <thread>
@@ -40,46 +40,23 @@ AUD_NAMESPACE_BEGIN
/**
* This device plays back through WASAPI, the Windows audio API.
*/
-class AUD_PLUGIN_API WASAPIDevice : public SoftwareDevice
+class AUD_PLUGIN_API WASAPIDevice : public ThreadedDevice
{
private:
- /**
- * Whether there is currently playback.
- */
- bool m_playing;
-
- /**
- * Whether the current playback should stop.
- */
- bool m_stop;
-
IMMDeviceEnumerator* m_imm_device_enumerator;
IMMDevice* m_imm_device;
IAudioClient* m_audio_client;
WAVEFORMATEXTENSIBLE m_wave_format_extensible;
/**
- * The streaming thread.
- */
- std::thread m_thread;
-
- /**
- * Starts the streaming thread.
- */
- AUD_LOCAL void start();
-
- /**
* Streaming thread main function.
*/
- AUD_LOCAL void updateStream();
+ AUD_LOCAL void runMixingThread();
// delete copy constructor and operator=
WASAPIDevice(const WASAPIDevice&) = delete;
WASAPIDevice& operator=(const WASAPIDevice&) = delete;
-protected:
- virtual void playing(bool playing);
-
public:
/**
* Opens the WASAPI audio device for playback.
diff --git a/extern/audaspace/src/devices/SoftwareDevice.cpp b/extern/audaspace/src/devices/SoftwareDevice.cpp
index c8c1c6081c2..7a2561515f4 100644
--- a/extern/audaspace/src/devices/SoftwareDevice.cpp
+++ b/extern/audaspace/src/devices/SoftwareDevice.cpp
@@ -737,7 +737,7 @@ void SoftwareDevice::mix(data_t* buffer, int length)
{
m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs));
- std::lock_guard<std::recursive_mutex> lock(m_mutex);
+ std::lock_guard<ILockable> lock(*this);
{
std::shared_ptr<SoftwareDevice::SoftwareHandle> sound;
@@ -880,7 +880,7 @@ std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<IReader> reader, b
// play sound
std::shared_ptr<SoftwareDevice::SoftwareHandle> sound = std::shared_ptr<SoftwareDevice::SoftwareHandle>(new SoftwareDevice::SoftwareHandle(this, reader, pitch, resampler, mapper, keep));
- std::lock_guard<std::recursive_mutex> lock(m_mutex);
+ std::lock_guard<ILockable> lock(*this);
m_playingSounds.push_back(sound);
@@ -897,7 +897,7 @@ std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<ISound> sound, boo
void SoftwareDevice::stopAll()
{
- std::lock_guard<std::recursive_mutex> lock(m_mutex);
+ std::lock_guard<ILockable> lock(*this);
while(!m_playingSounds.empty())
m_playingSounds.front()->stop();
diff --git a/extern/audaspace/src/devices/ThreadedDevice.cpp b/extern/audaspace/src/devices/ThreadedDevice.cpp
new file mode 100644
index 00000000000..44ceccb8a60
--- /dev/null
+++ b/extern/audaspace/src/devices/ThreadedDevice.cpp
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "devices/ThreadedDevice.h"
+
+#include <mutex>
+
+AUD_NAMESPACE_BEGIN
+
+void ThreadedDevice::start()
+{
+ std::lock_guard<ILockable> lock(*this);
+
+ // thread is still running, we can abort stopping it
+ if(m_stop)
+ m_stop = false;
+
+ // thread is not running, let's start it
+ else if(!m_playing)
+ {
+ if(m_thread.joinable())
+ m_thread.join();
+
+ m_playing = true;
+
+ m_thread = std::thread(&ThreadedDevice::runMixingThread, this);
+ }
+}
+
+void ThreadedDevice::playing(bool playing)
+{
+ if((!m_playing || m_stop) && playing)
+ start();
+ else
+ m_stop = true;
+}
+
+ThreadedDevice::ThreadedDevice() :
+ m_playing(false),
+ m_stop(false)
+{
+}
+
+void aud::ThreadedDevice::stopMixingThread()
+{
+ stopAll();
+
+ if(m_thread.joinable())
+ m_thread.join();
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/mantaflow/preprocessed/fileio/iovdb.cpp b/extern/mantaflow/preprocessed/fileio/iovdb.cpp
index e615741e0f7..1846ef7ecbb 100644
--- a/extern/mantaflow/preprocessed/fileio/iovdb.cpp
+++ b/extern/mantaflow/preprocessed/fileio/iovdb.cpp
@@ -29,10 +29,10 @@
#if OPENVDB == 1
# include "openvdb/openvdb.h"
-# include <openvdb/points/PointConversion.h>
-# include <openvdb/points/PointCount.h>
-# include <openvdb/tools/Clip.h>
-# include <openvdb/tools/Dense.h>
+# include "openvdb/points/PointConversion.h"
+# include "openvdb/points/PointCount.h"
+# include "openvdb/tools/Clip.h"
+# include "openvdb/tools/Dense.h"
#endif
#define POSITION_NAME "P"
@@ -519,7 +519,7 @@ int writeObjectsVDB(const string &filename,
}
}
- // Write only if the is at least one grid, optionally write with compression.
+ // Write only if there is at least one grid, optionally write with compression.
if (gridsVDB.size()) {
int vdb_flags = openvdb::io::COMPRESS_ACTIVE_MASK;
switch (compression) {
@@ -534,7 +534,8 @@ int writeObjectsVDB(const string &filename,
}
case COMPRESSION_BLOSC: {
# if OPENVDB_BLOSC == 1
- vdb_flags |= openvdb::io::COMPRESS_BLOSC;
+ // Cannot use |= here, causes segfault with blosc 1.5.0 (== recommended version)
+ vdb_flags = openvdb::io::COMPRESS_BLOSC;
# else
debMsg("OpenVDB was built without Blosc support, using Zip compression instead", 1);
vdb_flags |= openvdb::io::COMPRESS_ZIP;
diff --git a/extern/mantaflow/preprocessed/fluidsolver.h b/extern/mantaflow/preprocessed/fluidsolver.h
index 0c871bca3a1..6770f8b7b05 100644
--- a/extern/mantaflow/preprocessed/fluidsolver.h
+++ b/extern/mantaflow/preprocessed/fluidsolver.h
@@ -384,6 +384,7 @@ class FluidSolver : public PbClass {
GridStorage<Real> mGrids4dReal;
GridStorage<Vec3> mGrids4dVec;
GridStorage<Vec4> mGrids4dVec4;
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/general.h b/extern/mantaflow/preprocessed/general.h
index 50eac71e87e..8bf1c2e25de 100644
--- a/extern/mantaflow/preprocessed/general.h
+++ b/extern/mantaflow/preprocessed/general.h
@@ -42,7 +42,7 @@ inline void updateQtGui(bool full, int frame, float time, const std::string &cur
# ifdef _DEBUG
# define DEBUG 1
# endif // _DEBUG
-#endif // DEBUG
+#endif // DEBUG
// Standard exception
class Error : public std::exception {
diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h
index 1bb96fe3baa..03fd0112095 100644
--- a/extern/mantaflow/preprocessed/gitinfo.h
+++ b/extern/mantaflow/preprocessed/gitinfo.h
@@ -1,3 +1,3 @@
-#define MANTA_GIT_VERSION "commit 39b7a415721ecbf6643612a24e8eadd221aeb934"
+#define MANTA_GIT_VERSION "commit 9c505cd22e289b98c9aa717efba8ef3201c7e458"
diff --git a/extern/mantaflow/preprocessed/grid.h b/extern/mantaflow/preprocessed/grid.h
index 9c3d954771e..2c4296e78dd 100644
--- a/extern/mantaflow/preprocessed/grid.h
+++ b/extern/mantaflow/preprocessed/grid.h
@@ -389,6 +389,7 @@ class GridBase : public PbClass {
Real mDx;
bool m3D; // precomputed Z shift: to ensure 2D compatibility, always use this instead of sx*sy !
IndexInt mStrideZ;
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/grid4d.h b/extern/mantaflow/preprocessed/grid4d.h
index 9b64116fc9d..1741db590b7 100644
--- a/extern/mantaflow/preprocessed/grid4d.h
+++ b/extern/mantaflow/preprocessed/grid4d.h
@@ -326,6 +326,7 @@ class Grid4dBase : public PbClass {
// precomputed Z,T shift: to ensure 2D compatibility, always use this instead of sx*sy !
IndexInt mStrideZ;
IndexInt mStrideT;
+
public:
PbArgs _args;
}
@@ -950,6 +951,7 @@ template<class T> class Grid4d : public Grid4dBase {
protected:
T *mData;
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/levelset.h b/extern/mantaflow/preprocessed/levelset.h
index db542bb1fe6..ae162f73c3d 100644
--- a/extern/mantaflow/preprocessed/levelset.h
+++ b/extern/mantaflow/preprocessed/levelset.h
@@ -266,6 +266,7 @@ class LevelsetGrid : public Grid<Real> {
}
static Real invalidTimeValue();
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/mesh.h b/extern/mantaflow/preprocessed/mesh.h
index d3a69abc4ea..b5de66ce095 100644
--- a/extern/mantaflow/preprocessed/mesh.h
+++ b/extern/mantaflow/preprocessed/mesh.h
@@ -796,6 +796,7 @@ class Mesh : public PbClass {
std::vector<MeshDataImpl<int> *>
mMdataInt; //! indicate that mdata of this mesh is copied, and needs to be freed
bool mFreeMdata;
+
public:
PbArgs _args;
}
@@ -881,6 +882,7 @@ class MeshDataBase : public PbClass {
protected:
Mesh *mMesh;
+
public:
PbArgs _args;
}
@@ -1645,6 +1647,7 @@ template<class T> class MeshDataImpl : public MeshDataBase {
//! optionally , we might have an associated grid from which to grab new data
Grid<T> *mpGridSource; //! unfortunately , we need to distinguish mac vs regular vec3
bool mGridSourceMAC;
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/movingobs.h b/extern/mantaflow/preprocessed/movingobs.h
index 0661ddf5b37..83ef6ed0c9f 100644
--- a/extern/mantaflow/preprocessed/movingobs.h
+++ b/extern/mantaflow/preprocessed/movingobs.h
@@ -154,6 +154,7 @@ class MovingObstacle : public PbClass {
int mEmptyType;
int mID;
static int sIDcnt;
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/noisefield.h b/extern/mantaflow/preprocessed/noisefield.h
index 73c9de779ef..6ed8ac0012d 100644
--- a/extern/mantaflow/preprocessed/noisefield.h
+++ b/extern/mantaflow/preprocessed/noisefield.h
@@ -236,6 +236,7 @@ class WaveletNoiseField : public PbClass {
static int randomSeed;
// global reference count for noise tile
static std::atomic<int> mNoiseReferenceCount;
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/particle.h b/extern/mantaflow/preprocessed/particle.h
index 7fcc7e5ca32..7e0c64e6d03 100644
--- a/extern/mantaflow/preprocessed/particle.h
+++ b/extern/mantaflow/preprocessed/particle.h
@@ -205,6 +205,7 @@ class ParticleBase : public PbClass {
//! custom seed for particle systems, used by plugins
int mSeed; //! fix global random seed storage, used mainly by functions in this class
static int globalSeed;
+
public:
PbArgs _args;
}
@@ -628,6 +629,7 @@ template<class S> class ParticleSystem : public ParticleBase {
std::vector<S> mData;
//! reduce storage , called by doCompress
virtual void compress();
+
public:
PbArgs _args;
}
@@ -918,6 +920,7 @@ class ParticleIndexSystem : public ParticleSystem<ParticleIndexData> {
return -1;
}
};
+
public:
PbArgs _args;
}
@@ -982,6 +985,7 @@ template<class DATA, class CON> class ConnectedParticleSystem : public ParticleS
protected:
std::vector<CON> mSegments;
virtual void compress();
+
public:
PbArgs _args;
}
@@ -1071,6 +1075,7 @@ class ParticleDataBase : public PbClass {
protected:
ParticleBase *mpParticleSys;
+
public:
PbArgs _args;
}
@@ -1843,6 +1848,7 @@ template<class T> class ParticleDataImpl : public ParticleDataBase {
//! optionally , we might have an associated grid from which to grab new data
Grid<T> *mpGridSource; //! unfortunately , we need to distinguish mac vs regular vec3
bool mGridSourceMAC;
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/plugin/meshplugins.cpp b/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
index 043660db20b..cf315429d65 100644
--- a/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
+++ b/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
@@ -234,10 +234,10 @@ void subdivideMesh(
normalize(ne2);
// Real thisArea = sqrMag(cross(-e2,e0));
- // small angle approximation says sin(x) = arcsin(x) = x,
- // arccos(x) = pi/2 - arcsin(x),
- // cos(x) = dot(A,B),
- // so angle is approximately 1 - dot(A,B).
+ // small angle approximation says sin(x) = arcsin(x) = x,
+ // arccos(x) = pi/2 - arcsin(x),
+ // cos(x) = dot(A,B),
+ // so angle is approximately 1 - dot(A,B).
Real angle[3];
angle[0] = 1.0 - dot(ne0, -ne2);
angle[1] = 1.0 - dot(ne1, -ne0);
diff --git a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
index 7a1d8224d94..2f876376f53 100644
--- a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
+++ b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
@@ -2287,9 +2287,10 @@ struct knFlipComputePotentialTrappedAir : public KernelBase {
const Vec3 &vj = scaleFromManta * v.getCentered(x, y, z);
const Vec3 xij = xi - xj;
const Vec3 vij = vi - vj;
- Real h = !pot.is3D() ? 1.414 * radius :
- 1.732 * radius; // estimate sqrt(2)*radius resp. sqrt(3)*radius
- // for h, due to squared resp. cubic neighbor area
+ Real h = !pot.is3D() ?
+ 1.414 * radius :
+ 1.732 * radius; // estimate sqrt(2)*radius resp. sqrt(3)*radius for h, due
+ // to squared resp. cubic neighbor area
vdiff += norm(vij) * (1 - dot(getNormalized(vij), getNormalized(xij))) *
(1 - norm(xij) / h);
}
diff --git a/extern/mantaflow/preprocessed/shapes.h b/extern/mantaflow/preprocessed/shapes.h
index fa645389bfe..5a400eaed09 100644
--- a/extern/mantaflow/preprocessed/shapes.h
+++ b/extern/mantaflow/preprocessed/shapes.h
@@ -269,6 +269,7 @@ class Shape : public PbClass {
protected:
GridType mType;
+
public:
PbArgs _args;
}
@@ -319,6 +320,7 @@ class NullShape : public Shape {
{
gridSetConst<Real>(phi, 1000.0f);
}
+
public:
PbArgs _args;
}
@@ -394,6 +396,7 @@ class Box : public Shape {
protected:
Vec3 mP0, mP1;
+
public:
PbArgs _args;
}
@@ -455,6 +458,7 @@ class Sphere : public Shape {
protected:
Vec3 mCenter, mScale;
Real mRadius;
+
public:
PbArgs _args;
}
@@ -579,6 +583,7 @@ class Cylinder : public Shape {
protected:
Vec3 mCenter, mZDir;
Real mRadius, mZ;
+
public:
PbArgs _args;
}
@@ -655,6 +660,7 @@ class Slope : public Shape {
Real mAnglexy, mAngleyz;
Real mOrigin;
Vec3 mGs;
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/turbulencepart.h b/extern/mantaflow/preprocessed/turbulencepart.h
index 81c94d77722..5177aeb2d96 100644
--- a/extern/mantaflow/preprocessed/turbulencepart.h
+++ b/extern/mantaflow/preprocessed/turbulencepart.h
@@ -199,6 +199,7 @@ class TurbulenceParticleSystem : public ParticleSystem<TurbulenceParticleData> {
private:
WaveletNoiseField &noise;
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/vortexpart.h b/extern/mantaflow/preprocessed/vortexpart.h
index e48fbc7f507..8f80cf910eb 100644
--- a/extern/mantaflow/preprocessed/vortexpart.h
+++ b/extern/mantaflow/preprocessed/vortexpart.h
@@ -127,6 +127,7 @@ class VortexParticleSystem : public ParticleSystem<VortexParticleData> {
}
virtual ParticleBase *clone();
+
public:
PbArgs _args;
}
diff --git a/extern/mantaflow/preprocessed/vortexsheet.h b/extern/mantaflow/preprocessed/vortexsheet.h
index 01c32e4e806..0fc0f3a1258 100644
--- a/extern/mantaflow/preprocessed/vortexsheet.h
+++ b/extern/mantaflow/preprocessed/vortexsheet.h
@@ -240,6 +240,7 @@ class VortexSheetMesh : public Mesh {
VorticityChannel mVorticity;
TexCoord3Channel mTex1, mTex2;
TurbulenceChannel mTurb;
+
public:
PbArgs _args;
}
diff --git a/extern/smaa_areatex/CMakeLists.txt b/extern/smaa_areatex/CMakeLists.txt
new file mode 100644
index 00000000000..2386b0e7b79
--- /dev/null
+++ b/extern/smaa_areatex/CMakeLists.txt
@@ -0,0 +1,26 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2017, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): IRIE Shinsuke
+#
+# ***** END GPL LICENSE BLOCK *****
+
+add_executable(smaa_areatex smaa_areatex.cpp)
diff --git a/extern/smaa_areatex/README.blender b/extern/smaa_areatex/README.blender
new file mode 100644
index 00000000000..9c409142ae8
--- /dev/null
+++ b/extern/smaa_areatex/README.blender
@@ -0,0 +1,5 @@
+Project: smaa-cpp
+URL: https://github.com/iRi-E/smaa-cpp
+License: MIT
+Upstream version: 0.4.0
+Local modifications:
diff --git a/extern/smaa_areatex/smaa_areatex.cpp b/extern/smaa_areatex/smaa_areatex.cpp
new file mode 100644
index 00000000000..7a4ff3a9831
--- /dev/null
+++ b/extern/smaa_areatex/smaa_areatex.cpp
@@ -0,0 +1,1208 @@
+/**
+ * Copyright (C) 2016-2017 IRIE Shinsuke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * smaa_areatex.cpp version 0.4.0
+ *
+ * This is a part of smaa-cpp that is an implementation of
+ * Enhanced Subpixel Morphological Antialiasing (SMAA) written in C++.
+ *
+ * This program is C++ rewrite of AreaTex.py included in the original
+ * SMAA ditribution:
+ *
+ * https://github.com/iryoku/smaa/tree/master/Scripts
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include <cmath>
+
+/*------------------------------------------------------------------------------*/
+/* Type Definitions */
+
+class Int2;
+class Dbl2;
+
+class Int2 {
+public:
+ int x, y;
+
+ Int2() { this->x = this->y = 0; }
+ Int2(int x) { this->x = this->y = x; }
+ Int2(int x, int y) { this->x = x; this->y = y; }
+
+ operator Dbl2();
+
+ Int2 operator + (Int2 other) { return Int2(x + other.x, y + other.y); }
+ Int2 operator * (Int2 other) { return Int2(x * other.x, y * other.y); }
+};
+
+class Dbl2 {
+public:
+ double x, y;
+
+ Dbl2() { this->x = this->y = 0.0; }
+ Dbl2(double x) { this->x = this->y = x; }
+ Dbl2(double x, double y) { this->x = x; this->y = y; }
+
+ Dbl2 apply(double (* func)(double)) { return Dbl2(func(x), func(y)); }
+
+ operator Int2();
+
+ Dbl2 operator + (Dbl2 other) { return Dbl2(x + other.x, y + other.y); }
+ Dbl2 operator - (Dbl2 other) { return Dbl2(x - other.x, y - other.y); }
+ Dbl2 operator * (Dbl2 other) { return Dbl2(x * other.x, y * other.y); }
+ Dbl2 operator / (Dbl2 other) { return Dbl2(x / other.x, y / other.y); }
+ Dbl2 operator += (Dbl2 other) { return Dbl2(x += other.x, y += other.y); }
+ bool operator == (Dbl2 other) { return (x == other.x && y == other.y); }
+};
+
+Int2::operator Dbl2() { return Dbl2((double)x, (double)y); }
+Dbl2::operator Int2() { return Int2((int)x, (int)y); }
+
+/*------------------------------------------------------------------------------*/
+/* Data to Calculate Areatex */
+
+/* Texture sizes: */
+/* (it's quite possible that this is not easily configurable) */
+static const int SUBSAMPLES_ORTHO = 7;
+static const int SUBSAMPLES_DIAG = 5;
+static const int MAX_DIST_ORTHO_COMPAT = 16;
+static const int MAX_DIST_ORTHO = 20;
+static const int MAX_DIST_DIAG = 20;
+static const int TEX_SIZE_ORTHO = 80; /* 16 * 5 slots = 80 */
+static const int TEX_SIZE_DIAG = 80; /* 20 * 4 slots = 80 */
+
+/* Number of samples for calculating areas in the diagonal textures: */
+/* (diagonal areas are calculated using brute force sampling) */
+static const int SAMPLES_DIAG = 30;
+
+/* Maximum distance for smoothing u-shapes: */
+static const int SMOOTH_MAX_DISTANCE = 32;
+
+/*------------------------------------------------------------------------------*/
+/* Offset Tables */
+
+/* Offsets for subsample rendering */
+static const double subsample_offsets_ortho[SUBSAMPLES_ORTHO] = {
+ 0.0, /* 0 */
+ -0.25, /* 1 */
+ 0.25, /* 2 */
+ -0.125, /* 3 */
+ 0.125, /* 4 */
+ -0.375, /* 5 */
+ 0.375 /* 6 */
+};
+
+static const Dbl2 subsample_offsets_diag[SUBSAMPLES_DIAG] = {
+ { 0.00, 0.00}, /* 0 */
+ { 0.25, -0.25}, /* 1 */
+ {-0.25, 0.25}, /* 2 */
+ { 0.125, -0.125}, /* 3 */
+ {-0.125, 0.125} /* 4 */
+};
+
+/* Mapping offsets for placing each pattern subtexture into its place */
+enum edgesorthoIndices
+{
+ EDGESORTHO_NONE_NONE = 0,
+ EDGESORTHO_NONE_NEGA = 1,
+ EDGESORTHO_NONE_POSI = 2,
+ EDGESORTHO_NONE_BOTH = 3,
+ EDGESORTHO_NEGA_NONE = 4,
+ EDGESORTHO_NEGA_NEGA = 5,
+ EDGESORTHO_NEGA_POSI = 6,
+ EDGESORTHO_NEGA_BOTH = 7,
+ EDGESORTHO_POSI_NONE = 8,
+ EDGESORTHO_POSI_NEGA = 9,
+ EDGESORTHO_POSI_POSI = 10,
+ EDGESORTHO_POSI_BOTH = 11,
+ EDGESORTHO_BOTH_NONE = 12,
+ EDGESORTHO_BOTH_NEGA = 13,
+ EDGESORTHO_BOTH_POSI = 14,
+ EDGESORTHO_BOTH_BOTH = 15,
+};
+
+static const Int2 edgesortho_compat[16] = {
+ {0, 0}, {0, 1}, {0, 3}, {0, 4}, {1, 0}, {1, 1}, {1, 3}, {1, 4},
+ {3, 0}, {3, 1}, {3, 3}, {3, 4}, {4, 0}, {4, 1}, {4, 3}, {4, 4}
+};
+
+static const Int2 edgesortho[16] = {
+ {0, 0}, {0, 1}, {0, 2}, {0, 3}, {1, 0}, {1, 1}, {1, 2}, {1, 3},
+ {2, 0}, {2, 1}, {2, 2}, {2, 3}, {3, 0}, {3, 1}, {3, 2}, {3, 3}
+};
+
+enum edgesdiagIndices
+{
+ EDGESDIAG_NONE_NONE = 0,
+ EDGESDIAG_NONE_VERT = 1,
+ EDGESDIAG_NONE_HORZ = 2,
+ EDGESDIAG_NONE_BOTH = 3,
+ EDGESDIAG_VERT_NONE = 4,
+ EDGESDIAG_VERT_VERT = 5,
+ EDGESDIAG_VERT_HORZ = 6,
+ EDGESDIAG_VERT_BOTH = 7,
+ EDGESDIAG_HORZ_NONE = 8,
+ EDGESDIAG_HORZ_VERT = 9,
+ EDGESDIAG_HORZ_HORZ = 10,
+ EDGESDIAG_HORZ_BOTH = 11,
+ EDGESDIAG_BOTH_NONE = 12,
+ EDGESDIAG_BOTH_VERT = 13,
+ EDGESDIAG_BOTH_HORZ = 14,
+ EDGESDIAG_BOTH_BOTH = 15,
+};
+
+static const Int2 edgesdiag[16] = {
+ {0, 0}, {0, 1}, {0, 2}, {0, 3}, {1, 0}, {1, 1}, {1, 2}, {1, 3},
+ {2, 0}, {2, 1}, {2, 2}, {2, 3}, {3, 0}, {3, 1}, {3, 2}, {3, 3}
+};
+
+/*------------------------------------------------------------------------------*/
+/* Miscellaneous Utility Functions */
+
+/* Linear interpolation: */
+static Dbl2 lerp(Dbl2 a, Dbl2 b, double p)
+{
+ return a + (b - a) * Dbl2(p);
+}
+
+/* Saturates a value to [0..1] range: */
+static double saturate(double x)
+{
+ return 0.0 < x ? (x < 1.0 ? x : 1.0) : 0.0;
+}
+
+/*------------------------------------------------------------------------------*/
+/* Horizontal/Vertical Areas */
+
+class AreaOrtho {
+ double m_data[SUBSAMPLES_ORTHO][TEX_SIZE_ORTHO][TEX_SIZE_ORTHO][2];
+ bool m_compat;
+ bool m_orig_u;
+public:
+ AreaOrtho(bool compat, bool orig_u) : m_compat(compat), m_orig_u(orig_u) {}
+
+ double *getData() { return (double *)&m_data; }
+ Dbl2 getPixel(int offset_index, Int2 coords) {
+ return Dbl2(m_data[offset_index][coords.y][coords.x][0],
+ m_data[offset_index][coords.y][coords.x][1]);
+ }
+
+ void areaTex(int offset_index);
+private:
+ void putPixel(int offset_index, Int2 coords, Dbl2 pixel) {
+ m_data[offset_index][coords.y][coords.x][0] = pixel.x;
+ m_data[offset_index][coords.y][coords.x][1] = pixel.y;
+ }
+
+ Dbl2 smoothArea(double d, Dbl2 a1, Dbl2 a2);
+ Dbl2 makeQuad(int x, double d, double o);
+ Dbl2 area(Dbl2 p1, Dbl2 p2, int x);
+ Dbl2 calculate(int pattern, int left, int right, double offset);
+};
+
+/* Smoothing function for small u-patterns: */
+Dbl2 AreaOrtho::smoothArea(double d, Dbl2 a1, Dbl2 a2)
+{
+ Dbl2 b1 = (a1 * Dbl2(2.0)).apply(sqrt) * Dbl2(0.5);
+ Dbl2 b2 = (a2 * Dbl2(2.0)).apply(sqrt) * Dbl2(0.5);
+ double p = saturate(d / (double)SMOOTH_MAX_DISTANCE);
+ return lerp(b1, a1, p) + lerp(b2, a2, p);
+}
+
+/* Smoothing u-patterns by quadratic function: */
+Dbl2 AreaOrtho::makeQuad(int x, double d, double o)
+{
+ double r = (double)x;
+
+ /* fmin() below is a trick to smooth tiny u-patterns: */
+ return Dbl2(r, (1.0 - fmin(4.0, d) * r * (d - r) / (d * d)) * o);
+}
+
+/* Calculates the area under the line p1->p2, for the pixel x..x+1: */
+Dbl2 AreaOrtho::area(Dbl2 p1, Dbl2 p2, int x)
+{
+ Dbl2 d = p2 - p1;
+ double x1 = (double)x;
+ double x2 = x1 + 1.0;
+
+ if ((x1 >= p1.x && x1 < p2.x) || (x2 > p1.x && x2 <= p2.x)) { /* inside? */
+ double y1 = p1.y + (x1 - p1.x) * d.y / d.x;
+ double y2 = p1.y + (x2 - p1.x) * d.y / d.x;
+
+ if ((copysign(1.0, y1) == copysign(1.0, y2) ||
+ fabs(y1) < 1e-4 || fabs(y2) < 1e-4)) { /* trapezoid? */
+ double a = (y1 + y2) / 2.0;
+ if (a < 0.0)
+ return Dbl2(fabs(a), 0.0);
+ else
+ return Dbl2(0.0, fabs(a));
+ }
+ else { /* Then, we got two triangles: */
+ double x = p1.x - p1.y * d.x / d.y, xi;
+ double a1 = x > p1.x ? y1 * modf(x, &xi) / 2.0 : 0.0;
+ double a2 = x < p2.x ? y2 * (1.0 - modf(x, &xi)) / 2.0 : 0.0;
+ double a = fabs(a1) > fabs(a2) ? a1 : -a2;
+ if (a < 0.0)
+ return Dbl2(fabs(a1), fabs(a2));
+ else
+ return Dbl2(fabs(a2), fabs(a1));
+ }
+ }
+ else
+ return Dbl2(0.0, 0.0);
+}
+
+/* Calculates the area for a given pattern and distances to the left and to the */
+/* right, biased by an offset: */
+Dbl2 AreaOrtho::calculate(int pattern, int left, int right, double offset)
+{
+ Dbl2 a1, a2;
+
+ /*
+ * o1 |
+ * .-------´
+ * o2 |
+ *
+ * <---d--->
+ */
+ double d = (double)(left + right + 1);
+
+ double o1 = 0.5 + offset;
+ double o2 = 0.5 + offset - 1.0;
+
+ switch (pattern) {
+ case EDGESORTHO_NONE_NONE:
+ {
+ /*
+ *
+ * ------
+ *
+ */
+ return Dbl2(0.0, 0.0);
+ break;
+ }
+ case EDGESORTHO_POSI_NONE:
+ {
+ /*
+ *
+ * .------
+ * |
+ *
+ * We only offset L patterns in the crossing edge side, to make it
+ * converge with the unfiltered pattern 0 (we don't want to filter the
+ * pattern 0 to avoid artifacts).
+ */
+ if (left <= right)
+ return area(Dbl2(0.0, o2), Dbl2(d / 2.0, 0.0), left);
+ else
+ return Dbl2(0.0, 0.0);
+ break;
+ }
+ case EDGESORTHO_NONE_POSI:
+ {
+ /*
+ *
+ * ------.
+ * |
+ */
+ if (left >= right)
+ return area(Dbl2(d / 2.0, 0.0), Dbl2(d, o2), left);
+ else
+ return Dbl2(0.0, 0.0);
+ break;
+ }
+ case EDGESORTHO_POSI_POSI:
+ {
+ /*
+ *
+ * .------.
+ * | |
+ */
+ if (m_orig_u) {
+ a1 = area(Dbl2(0.0, o2), Dbl2(d / 2.0, 0.0), left);
+ a2 = area(Dbl2(d / 2.0, 0.0), Dbl2(d, o2), left);
+ return smoothArea(d, a1, a2);
+ }
+ else
+ return area(makeQuad(left, d, o2), makeQuad(left + 1, d, o2), left);
+ break;
+ }
+ case EDGESORTHO_NEGA_NONE:
+ {
+ /*
+ * |
+ * `------
+ *
+ */
+ if (left <= right)
+ return area(Dbl2(0.0, o1), Dbl2(d / 2.0, 0.0), left);
+ else
+ return Dbl2(0.0, 0.0);
+ break;
+ }
+ case EDGESORTHO_BOTH_NONE:
+ {
+ /*
+ * |
+ * +------
+ * |
+ */
+ return Dbl2(0.0, 0.0);
+ break;
+ }
+ case EDGESORTHO_NEGA_POSI:
+ {
+ /*
+ * |
+ * `------.
+ * |
+ *
+ * A problem of not offseting L patterns (see above), is that for certain
+ * max search distances, the pixels in the center of a Z pattern will
+ * detect the full Z pattern, while the pixels in the sides will detect a
+ * L pattern. To avoid discontinuities, we blend the full offsetted Z
+ * revectorization with partially offsetted L patterns.
+ */
+ if (fabs(offset) > 0.0) {
+ a1 = area(Dbl2(0.0, o1), Dbl2(d, o2), left);
+ a2 = area(Dbl2(0.0, o1), Dbl2(d / 2.0, 0.0), left);
+ a2 += area(Dbl2(d / 2.0, 0.0), Dbl2(d, o2), left);
+ return (a1 + a2) / Dbl2(2.0);
+ }
+ else
+ return area(Dbl2(0.0, o1), Dbl2(d, o2), left);
+ break;
+ }
+ case EDGESORTHO_BOTH_POSI:
+ {
+ /*
+ * |
+ * +------.
+ * | |
+ */
+ return area(Dbl2(0.0, o1), Dbl2(d, o2), left);
+ break;
+ }
+ case EDGESORTHO_NONE_NEGA:
+ {
+ /*
+ * |
+ * ------´
+ *
+ */
+ if (left >= right)
+ return area(Dbl2(d / 2.0, 0.0), Dbl2(d, o1), left);
+ else
+ return Dbl2(0.0, 0.0);
+ break;
+ }
+ case EDGESORTHO_POSI_NEGA:
+ {
+ /*
+ * |
+ * .------´
+ * |
+ */
+ if (fabs(offset) > 0.0) {
+ a1 = area(Dbl2(0.0, o2), Dbl2(d, o1), left);
+ a2 = area(Dbl2(0.0, o2), Dbl2(d / 2.0, 0.0), left);
+ a2 += area(Dbl2(d / 2.0, 0.0), Dbl2(d, o1), left);
+ return (a1 + a2) / Dbl2(2.0);
+ }
+ else
+ return area(Dbl2(0.0, o2), Dbl2(d, o1), left);
+ break;
+ }
+ case EDGESORTHO_NONE_BOTH:
+ {
+ /*
+ * |
+ * ------+
+ * |
+ */
+ return Dbl2(0.0, 0.0);
+ break;
+ }
+ case EDGESORTHO_POSI_BOTH:
+ {
+ /*
+ * |
+ * .------+
+ * | |
+ */
+ return area(Dbl2(0.0, o2), Dbl2(d, o1), left);
+ break;
+ }
+ case EDGESORTHO_NEGA_NEGA:
+ {
+ /*
+ * | |
+ * `------´
+ *
+ */
+ if (m_orig_u) {
+ a1 = area(Dbl2(0.0, o1), Dbl2(d / 2.0, 0.0), left);
+ a2 = area(Dbl2(d / 2.0, 0.0), Dbl2(d, o1), left);
+ return smoothArea(d, a1, a2);
+ }
+ else
+ return area(makeQuad(left, d, o1), makeQuad(left + 1, d, o1), left);
+ break;
+ }
+ case EDGESORTHO_BOTH_NEGA:
+ {
+ /*
+ * | |
+ * +------´
+ * |
+ */
+ return area(Dbl2(0.0, o2), Dbl2(d, o1), left);
+ break;
+ }
+ case EDGESORTHO_NEGA_BOTH:
+ {
+ /*
+ * | |
+ * `------+
+ * |
+ */
+ return area(Dbl2(0.0, o1), Dbl2(d, o2), left);
+ break;
+ }
+ case EDGESORTHO_BOTH_BOTH:
+ {
+ /*
+ * | |
+ * +------+
+ * | |
+ */
+ return Dbl2(0.0, 0.0);
+ break;
+ }
+ }
+
+ return Dbl2(0.0, 0.0);
+}
+
+/*------------------------------------------------------------------------------*/
+/* Diagonal Areas */
+
+class AreaDiag {
+ double m_data[SUBSAMPLES_DIAG][TEX_SIZE_DIAG][TEX_SIZE_DIAG][2];
+ bool m_numeric;
+ bool m_orig_u;
+public:
+ AreaDiag(bool numeric, bool orig_u) : m_numeric(numeric), m_orig_u(orig_u) {}
+
+ double *getData() { return (double *)&m_data; }
+ Dbl2 getPixel(int offset_index, Int2 coords) {
+ return Dbl2(m_data[offset_index][coords.y][coords.x][0],
+ m_data[offset_index][coords.y][coords.x][1]);
+ }
+
+ void areaTex(int offset_index);
+private:
+ void putPixel(int offset_index, Int2 coords, Dbl2 pixel) {
+ m_data[offset_index][coords.y][coords.x][0] = pixel.x;
+ m_data[offset_index][coords.y][coords.x][1] = pixel.y;
+ }
+
+ double area1(Dbl2 p1, Dbl2 p2, Int2 p);
+ Dbl2 area(Dbl2 p1, Dbl2 p2, int left);
+ Dbl2 areaTriangle(Dbl2 p1L, Dbl2 p2L, Dbl2 p1R, Dbl2 p2R, int left);
+ Dbl2 calculate(int pattern, int left, int right, Dbl2 offset);
+};
+
+/* Calculates the area under the line p1->p2 for the pixel 'p' using brute */
+/* force sampling: */
+/* (quick and dirty solution, but it works) */
+double AreaDiag::area1(Dbl2 p1, Dbl2 p2, Int2 p)
+{
+ if (p1 == p2)
+ return 1.0;
+
+ double xm = (p1.x + p2.x) / 2.0, ym = (p1.y + p2.y) / 2.0;
+ double a = p2.y - p1.y;
+ double b = p1.x - p2.x;
+ int count = 0;
+
+ for (int ix = 0; ix < SAMPLES_DIAG; ix++) {
+ double x = (double)p.x + (double)ix / (double)(SAMPLES_DIAG - 1);
+ for (int iy = 0; iy < SAMPLES_DIAG; iy++) {
+ double y = (double)p.y + (double)iy / (double)(SAMPLES_DIAG - 1);
+ if (a * (x - xm) + b * (y - ym) > 0.0) /* inside? */
+ count++;
+ }
+ }
+ return (double)count / (double)(SAMPLES_DIAG * SAMPLES_DIAG);
+}
+
+/* Calculates the area under the line p1->p2: */
+/* (includes the pixel and its opposite) */
+Dbl2 AreaDiag::area(Dbl2 p1, Dbl2 p2, int left)
+{
+ if (m_numeric) {
+ double a1 = area1(p1, p2, Int2(1, 0) + Int2(left));
+ double a2 = area1(p1, p2, Int2(1, 1) + Int2(left));
+ return Dbl2(1.0 - a1, a2);
+ }
+
+ /* Calculates the area under the line p1->p2 for the pixel 'p' analytically */
+ Dbl2 d = p2 - p1;
+ if (d.x == 0.0)
+ return Dbl2(0.0, 1.0);
+
+ double x1 = (double)(1 + left);
+ double x2 = x1 + 1.0;
+ double ymid = x1;
+ double xtop = p1.x + (ymid + 1.0 - p1.y) * d.x / d.y;
+ double xmid = p1.x + (ymid - p1.y) * d.x / d.y;
+ double xbot = p1.x + (ymid - 1.0 - p1.y) * d.x / d.y;
+
+ double y1 = p1.y + (x1 - p1.x) * d.y / d.x;
+ double y2 = p1.y + (x2 - p1.x) * d.y / d.x;
+ double fy1 = y1 - floor(y1);
+ double fy2 = y2 - floor(y2);
+ int iy1 = (int)floor(y1 - ymid);
+ int iy2 = (int)floor(y2 - ymid);
+
+ if (iy1 <= -2) {
+ if (iy2 == -1)
+ return Dbl2(1.0 - (x2 - xbot) * fy2 * 0.5, 0.0);
+ else if (iy2 == 0)
+ return Dbl2((xmid + xbot) * 0.5 - x1, (x2 - xmid) * fy2 * 0.5);
+ else if (iy2 >= 1)
+ return Dbl2((xmid + xbot) * 0.5 - x1, x2 - (xtop + xmid) * 0.5);
+ else /* iy2 < -1 */
+ return Dbl2(1.0, 0.0);
+ }
+ else if (iy1 == -1) {
+ if (iy2 == -1)
+ return Dbl2(1.0 - (fy1 + fy2) * 0.5, 0.0);
+ else if (iy2 == 0)
+ return Dbl2((xmid - x1) * (1.0 - fy1) * 0.5, (x2 - xmid) * fy2 * 0.5);
+ else if (iy2 >= 1)
+ return Dbl2((xmid - x1) * (1.0 - fy1) * 0.5, x2 - (xtop + xmid) * 0.5);
+ else /* iy2 < -1 */
+ return Dbl2(1.0 - (xbot - x1) * fy1 * 0.5, 0.0);
+ }
+ else if (iy1 == 0) {
+ if (iy2 == -1)
+ return Dbl2((x2 - xmid) * (1.0 - fy2) * 0.5, (xmid - x1) * fy1 * 0.5);
+ else if (iy2 == 0)
+ return Dbl2(0.0, (fy1 + fy2) * 0.5);
+ else if (iy2 >= 1)
+ return Dbl2(0.0, 1.0 - (xtop - x1) * (1.0 - fy1) * 0.5);
+ else /* iy2 < -1 */
+ return Dbl2(x2 - (xmid + xbot) * 0.5, (xmid - x1) * fy1 * 0.5);
+ }
+ else { /* iy1 > 0 */
+ if (iy2 == -1)
+ return Dbl2((x2 - xtop) * (1.0 - fy2) * 0.5, (xtop + xmid) * 0.5 - x1);
+ else if (iy2 == 0)
+ return Dbl2(0.0, 1.0 - (x1 - xtop) * (1.0 - fy2) * 0.5);
+ else if (iy2 >= 1)
+ return Dbl2(0.0, 1.0);
+ else /* iy2 < -1 */
+ return Dbl2(x2 - (xmid + xbot) * 0.5, (xtop + xmid) * 0.5 - x1);
+ }
+}
+
+/* Calculate u-patterns using a triangle: */
+Dbl2 AreaDiag::areaTriangle(Dbl2 p1L, Dbl2 p2L, Dbl2 p1R, Dbl2 p2R, int left)
+{
+ double x1 = (double)(1 + left);
+ double x2 = x1 + 1.0;
+
+ Dbl2 dL = p2L - p1L;
+ Dbl2 dR = p2R - p1R;
+ double xm = ((p1L.x * dL.y / dL.x - p1L.y) - (p1R.x * dR.y / dR.x - p1R.y)) / (dL.y / dL.x - dR.y / dR.x);
+
+ double y1 = (x1 < xm) ? p1L.y + (x1 - p1L.x) * dL.y / dL.x : p1R.y + (x1 - p1R.x) * dR.y / dR.x;
+ double y2 = (x2 < xm) ? p1L.y + (x2 - p1L.x) * dL.y / dL.x : p1R.y + (x2 - p1R.x) * dR.y / dR.x;
+
+ return area(Dbl2(x1, y1), Dbl2(x2, y2), left);
+}
+
+/* Calculates the area for a given pattern and distances to the left and to the */
+/* right, biased by an offset: */
+Dbl2 AreaDiag::calculate(int pattern, int left, int right, Dbl2 offset)
+{
+ Dbl2 a1, a2;
+
+ double d = (double)(left + right + 1);
+
+ /*
+ * There is some Black Magic around diagonal area calculations. Unlike
+ * orthogonal patterns, the 'null' pattern (one without crossing edges) must be
+ * filtered, and the ends of both the 'null' and L patterns are not known: L
+ * and U patterns have different endings, and we don't know what is the
+ * adjacent pattern. So, what we do is calculate a blend of both possibilites.
+ */
+ switch (pattern) {
+ case EDGESDIAG_NONE_NONE:
+ {
+ /*
+ *
+ * .-´
+ * .-´
+ * .-´
+ * .-´
+ * ´
+ *
+ */
+ a1 = area(Dbl2(1.0, 1.0), Dbl2(1.0, 1.0) + Dbl2(d), left); /* 1st possibility */
+ a2 = area(Dbl2(1.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d), left); /* 2nd possibility */
+ return (a1 + a2) / Dbl2(2.0); /* Blend them */
+ break;
+ }
+ case EDGESDIAG_VERT_NONE:
+ {
+ /*
+ *
+ * .-´
+ * .-´
+ * .-´
+ * .-´
+ * |
+ * |
+ */
+ a1 = area(Dbl2(1.0, 0.0) + offset, Dbl2(0.0, 0.0) + Dbl2(d), left);
+ a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d), left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_NONE_HORZ:
+ {
+ /*
+ *
+ * .----
+ * .-´
+ * .-´
+ * .-´
+ * ´
+ *
+ */
+ a1 = area(Dbl2(0.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ a2 = area(Dbl2(1.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_VERT_HORZ:
+ {
+ /*
+ *
+ * .----
+ * .-´
+ * .-´
+ * .-´
+ * |
+ * |
+ */
+ if (m_orig_u)
+ return area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ else
+ return areaTriangle(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d),
+ Dbl2(0.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ break;
+ }
+ case EDGESDIAG_HORZ_NONE:
+ {
+ /*
+ *
+ * .-´
+ * .-´
+ * .-´
+ * ----´
+ *
+ *
+ */
+ a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(0.0, 0.0) + Dbl2(d), left);
+ a2 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d), left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_BOTH_NONE:
+ {
+ /*
+ *
+ * .-´
+ * .-´
+ * .-´
+ * --.-´
+ * |
+ * |
+ */
+ a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(0.0, 0.0) + Dbl2(d), left);
+ a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d), left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_HORZ_HORZ:
+ {
+ /*
+ *
+ * .----
+ * .-´
+ * .-´
+ * ----´
+ *
+ *
+ */
+ return area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ break;
+ }
+ case EDGESDIAG_BOTH_HORZ:
+ {
+ /*
+ *
+ * .----
+ * .-´
+ * .-´
+ * --.-´
+ * |
+ * |
+ */
+ a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_NONE_VERT:
+ {
+ /*
+ * |
+ * |
+ * .-´
+ * .-´
+ * .-´
+ * ´
+ *
+ */
+ a1 = area(Dbl2(0.0, 0.0), Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ a2 = area(Dbl2(1.0, 0.0), Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_VERT_VERT:
+ {
+ /*
+ * |
+ * |
+ * .-´
+ * .-´
+ * .-´
+ * |
+ * |
+ */
+ return area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ break;
+ }
+ case EDGESDIAG_NONE_BOTH:
+ {
+ /*
+ * |
+ * .----
+ * .-´
+ * .-´
+ * .-´
+ * ´
+ *
+ */
+ a1 = area(Dbl2(0.0, 0.0), Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ a2 = area(Dbl2(1.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_VERT_BOTH:
+ {
+ /*
+ * |
+ * .----
+ * .-´
+ * .-´
+ * .-´
+ * |
+ * |
+ */
+ a1 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_HORZ_VERT:
+ {
+ /*
+ * |
+ * |
+ * .-´
+ * .-´
+ * ----´
+ *
+ *
+ */
+ if (m_orig_u)
+ return area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ else
+ return areaTriangle(Dbl2(1.0, 1.0) + offset, Dbl2(2.0, 1.0) + Dbl2(d),
+ Dbl2(1.0, 0.0), Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ break;
+ }
+ case EDGESDIAG_BOTH_VERT:
+ {
+ /*
+ * |
+ * |
+ * .-´
+ * .-´
+ * --.-´
+ * |
+ * |
+ */
+ a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_HORZ_BOTH:
+ {
+ /*
+ * |
+ * .----
+ * .-´
+ * .-´
+ * ----´
+ *
+ *
+ */
+ a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ a2 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ case EDGESDIAG_BOTH_BOTH:
+ {
+ /*
+ * |
+ * .----
+ * .-´
+ * .-´
+ * --.-´
+ * |
+ * |
+ */
+ a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left);
+ a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left);
+ return (a1 + a2) / Dbl2(2.0);
+ break;
+ }
+ }
+
+ return Dbl2(0.0, 0.0);
+}
+
+/*------------------------------------------------------------------------------*/
+/* Main Loops */
+
+void AreaOrtho::areaTex(int offset_index)
+{
+ double offset = subsample_offsets_ortho[offset_index];
+ int max_dist = m_compat ? MAX_DIST_ORTHO_COMPAT : MAX_DIST_ORTHO;
+
+ for (int pattern = 0; pattern < 16; pattern++) {
+ Int2 e = Int2(max_dist) * (m_compat ? edgesortho_compat : edgesortho)[pattern];
+ for (int left = 0; left < max_dist; left++) {
+ for (int right = 0; right < max_dist; right++) {
+ Dbl2 p = calculate(pattern, left * left, right * right, offset);
+ Int2 coords = e + Int2(left, right);
+
+ putPixel(offset_index, coords, p);
+ }
+ }
+ }
+ return;
+}
+
+void AreaDiag::areaTex(int offset_index)
+{
+ Dbl2 offset = subsample_offsets_diag[offset_index];
+
+ for (int pattern = 0; pattern < 16; pattern++) {
+ Int2 e = Int2(MAX_DIST_DIAG) * edgesdiag[pattern];
+ for (int left = 0; left < MAX_DIST_DIAG; left++) {
+ for (int right = 0; right < MAX_DIST_DIAG; right++) {
+ Dbl2 p = calculate(pattern, left, right, offset);
+ Int2 coords = e + Int2(left, right);
+
+ putPixel(offset_index, coords, p);
+ }
+ }
+ }
+ return;
+}
+
+/*------------------------------------------------------------------------------*/
+/* Write File to Specified Location on Disk */
+
+/* C/C++ source code (arrays of floats) */
+static void write_double_array(FILE *fp, const double *ptr, int length, const char *array_name, bool quantize)
+{
+ fprintf(fp, "static const float %s[%d] = {", array_name, length);
+
+ for (int n = 0; n < length; n++) {
+ if (n > 0)
+ fprintf(fp, ",");
+ fprintf(fp, (n % 8 != 0) ? " " : "\n\t");
+
+ if (quantize)
+ fprintf(fp, "%3d / 255.0", (int)(*(ptr++) * 255.0));
+ else
+ fprintf(fp, "%1.8lf", *(ptr++));
+ }
+
+ fprintf(fp, "\n};\n");
+}
+
+static void write_csource(AreaOrtho *ortho, AreaDiag *diag, FILE *fp, bool subsampling, bool quantize)
+{
+ fprintf(fp, "/* This file was generated by smaa_areatex.cpp */\n");
+
+ fprintf(fp, "\n/* Horizontal/Vertical Areas */\n");
+ write_double_array(fp, ortho->getData(),
+ TEX_SIZE_ORTHO * TEX_SIZE_ORTHO * 2 * (subsampling ? SUBSAMPLES_ORTHO : 1),
+ "areatex", quantize);
+
+ fprintf(fp, "\n/* Diagonal Areas */\n");
+ write_double_array(fp, diag->getData(),
+ TEX_SIZE_DIAG * TEX_SIZE_DIAG * 2 * (subsampling ? SUBSAMPLES_DIAG : 1),
+ "areatex_diag", quantize);
+}
+
+/* .tga File (RGBA 32bit uncompressed) */
+static void write_tga(AreaOrtho *ortho, AreaDiag *diag, FILE *fp, bool subsampling)
+{
+ int subsamples = subsampling ? SUBSAMPLES_ORTHO : 1;
+ unsigned char header[18] = {0, 0,
+ 2, /* uncompressed RGB */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, /* 32bit */
+ 8}; /* 8bit alpha, left to right, bottom to top */
+
+ /* Set width and height */
+ header[12] = (TEX_SIZE_ORTHO + TEX_SIZE_DIAG) & 0xff;
+ header[13] = ((TEX_SIZE_ORTHO + TEX_SIZE_DIAG) >> 8) & 0xff;
+ header[14] = (subsamples * TEX_SIZE_ORTHO) & 0xff;
+ header[15] = ((subsamples * TEX_SIZE_ORTHO) >> 8) & 0xff;
+
+ /* Write .tga header */
+ fwrite(header, sizeof(unsigned char), sizeof(header) / sizeof(unsigned char), fp);
+
+ /* Write pixel data */
+ for (int i = subsamples - 1; i >= 0; i--) {
+ for (int y = TEX_SIZE_ORTHO - 1; y >= 0; y--) {
+ for (int x = 0; x < TEX_SIZE_ORTHO; x++) {
+ Dbl2 p = ortho->getPixel(i, Int2(x, y));
+ fputc(0, fp); /* B */
+ fputc((unsigned char)(p.y * 255.0), fp); /* G */
+ fputc((unsigned char)(p.x * 255.0), fp); /* R */
+ fputc(0, fp); /* A */
+ }
+
+ for (int x = 0; x < TEX_SIZE_DIAG; x++) {
+ if (i < SUBSAMPLES_DIAG) {
+ Dbl2 p = diag->getPixel(i, Int2(x, y));
+ fputc(0, fp); /* B */
+ fputc((unsigned char)(p.y * 255.0), fp); /* G */
+ fputc((unsigned char)(p.x * 255.0), fp); /* R */
+ fputc(0, fp); /* A */
+ }
+ else {
+ fputc(0, fp);
+ fputc(0, fp);
+ fputc(0, fp);
+ fputc(0, fp);
+ }
+ }
+ }
+ }
+}
+
+/* .raw File (R8G8 raw data) */
+static void write_raw(AreaOrtho *ortho, AreaDiag *diag, FILE *fp, bool subsampling)
+{
+ int subsamples = subsampling ? SUBSAMPLES_ORTHO : 1;
+
+ /* Write pixel data */
+ for (int i = 0; i < subsamples; i++) {
+ for (int y = 0; y < TEX_SIZE_ORTHO; y++) {
+ for (int x = 0; x < TEX_SIZE_ORTHO; x++) {
+ Dbl2 p = ortho->getPixel(i, Int2(x, y));
+ fputc((unsigned char)(p.x * 255.0), fp); /* R */
+ fputc((unsigned char)(p.y * 255.0), fp); /* G */
+ }
+
+ for (int x = 0; x < TEX_SIZE_DIAG; x++) {
+ if (i < SUBSAMPLES_DIAG) {
+ Dbl2 p = diag->getPixel(i, Int2(x, y));
+ fputc((unsigned char)(p.x * 255.0), fp); /* R */
+ fputc((unsigned char)(p.y * 255.0), fp); /* G */
+ }
+ else {
+ fputc(0, fp);
+ fputc(0, fp);
+ }
+ }
+ }
+ }
+}
+
+static int generate_file(AreaOrtho *ortho, AreaDiag *diag, const char *path, bool subsampling, bool quantize, bool tga, bool raw)
+{
+ FILE *fp = fopen(path, tga ? "wb" : "w");
+
+ if (!fp) {
+ fprintf(stderr, "Unable to open file: %s\n", path);
+ return 1;
+ }
+
+ // fprintf(stderr, "Generating %s\n", path);
+
+ if (tga)
+ write_tga(ortho, diag, fp, subsampling);
+ else if (raw)
+ write_raw(ortho, diag, fp, subsampling);
+ else
+ write_csource(ortho, diag, fp, subsampling, quantize);
+
+ fclose(fp);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ bool subsampling = false;
+ bool quantize = false;
+ bool tga = false;
+ bool raw = false;
+ bool compat = false;
+ bool numeric = false;
+ bool orig_u = false;
+ bool help = false;
+ char *outfile = NULL;
+ int status = 0;
+
+ for (int i = 1; i < argc; i++) {
+ char *ptr = argv[i];
+ if (*ptr++ == '-' && *ptr != '\0') {
+ char c;
+ while ((c = *ptr++) != '\0') {
+ if (c == 's')
+ subsampling = true;
+ else if (c == 'q')
+ quantize = true;
+ else if (c == 't')
+ tga = true;
+ else if (c == 'r')
+ raw = true;
+ else if (c == 'c')
+ compat = true;
+ else if (c == 'n')
+ numeric = true;
+ else if (c == 'u')
+ orig_u = true;
+ else if (c == 'h')
+ help = true;
+ else {
+ fprintf(stderr, "Unknown option: -%c\n", c);
+ status = 1;
+ break;
+ }
+ }
+ }
+ else if (outfile) {
+ fprintf(stderr, "Too much file names: %s, %s\n", outfile, argv[i]);
+ status = 1;
+ }
+ else
+ outfile = argv[i];
+
+ if (status != 0)
+ break;
+ }
+
+ if (status == 0 && !help && !outfile) {
+ fprintf(stderr, "File name was not specified.\n");
+ status = 1;
+ }
+
+ if (status != 0 || help) {
+ fprintf(stderr, "Usage: %s [OPTION]... OUTFILE\n", argv[0]);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -s Calculate data for subpixel rendering\n");
+ fprintf(stderr, " -q Quantize data to 256 levels\n");
+ fprintf(stderr, " -t Write TGA image instead of C/C++ source\n");
+ fprintf(stderr, " -r Write R8G8 raw image instead of C/C++ source\n");
+ fprintf(stderr, " -c Generate compatible orthogonal data that subtexture size is 16\n");
+ fprintf(stderr, " -n Numerically calculate diagonal data using brute force sampling\n");
+ fprintf(stderr, " -u Process orthogonal / diagonal U patterns in older ways\n");
+ fprintf(stderr, " -h Print this help and exit\n");
+ fprintf(stderr, "File name OUTFILE usually should have an extension such as .c, .h, or .tga,\n");
+ fprintf(stderr, "except for a special name '-' that means standard output.\n\n");
+ fprintf(stderr, "Example:\n");
+ fprintf(stderr, " Generate TGA file exactly same as AreaTexDX10.tga bundled with the\n");
+ fprintf(stderr, " original implementation:\n\n");
+ fprintf(stderr, " $ smaa_areatex -stcnu AreaTexDX10.tga\n\n");
+ return status;
+ }
+
+ AreaOrtho *ortho = new AreaOrtho(compat, orig_u);
+ AreaDiag *diag = new AreaDiag(numeric, orig_u);
+
+ /* Calculate areatex data */
+ for (int i = 0; i < (subsampling ? SUBSAMPLES_ORTHO : 1); i++)
+ ortho->areaTex(i);
+
+ for (int i = 0; i < (subsampling ? SUBSAMPLES_DIAG : 1); i++)
+ diag->areaTex(i);
+
+ /* Generate .tga, .raw, or C/C++ source file, or write the data to stdout */
+ if (strcmp(outfile, "-") != 0)
+ status = generate_file(ortho, diag, outfile, subsampling, quantize, tga, raw);
+ else if (tga)
+ write_tga(ortho, diag, stdout, subsampling);
+ else if (raw)
+ write_raw(ortho, diag, stdout, subsampling);
+ else
+ write_csource(ortho, diag, stdout, subsampling, quantize);
+
+ delete ortho;
+ delete diag;
+
+ return status;
+}
+
+/* smaa_areatex.cpp ends here */