mirror of https://github.com/OpenRCT2/OpenRCT2.git
Put a number of OpenRCT2::Ui items in the OpenRCT2::Ui namespace
This commit is contained in:
parent
dec5140f20
commit
cb100db56e
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <SDL.h>
|
||||
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
SDLException::SDLException(const std::string& message)
|
||||
: runtime_error(message.c_str())
|
||||
{
|
||||
|
|
|
@ -12,19 +12,22 @@
|
|||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* An exception which wraps an SDL error.
|
||||
*/
|
||||
class SDLException : public std::runtime_error
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
public:
|
||||
explicit SDLException(const std::string& message);
|
||||
|
||||
explicit SDLException(const char* message);
|
||||
|
||||
/**
|
||||
* Throws an SDL exception with a message containing the given call information
|
||||
* and the message given by SDL_GetError.
|
||||
* An exception which wraps an SDL error.
|
||||
*/
|
||||
static void Throw(const char* call);
|
||||
};
|
||||
class SDLException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit SDLException(const std::string& message);
|
||||
|
||||
explicit SDLException(const char* message);
|
||||
|
||||
/**
|
||||
* Throws an SDL exception with a message containing the given call information
|
||||
* and the message given by SDL_GetError.
|
||||
*/
|
||||
static void Throw(const char* call);
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -20,35 +20,35 @@ namespace OpenRCT2
|
|||
{
|
||||
struct IContext;
|
||||
struct IPlatformEnvironment;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
struct FileDialogDesc;
|
||||
class InGameConsole;
|
||||
struct IUiContext;
|
||||
|
||||
struct IPlatformUiContext
|
||||
{
|
||||
virtual ~IPlatformUiContext() = default;
|
||||
virtual void SetWindowIcon(SDL_Window* window) abstract;
|
||||
virtual bool IsSteamOverlayAttached() abstract;
|
||||
|
||||
virtual void ShowMessageBox(SDL_Window* window, const std::string& message) abstract;
|
||||
virtual bool HasMenuSupport() abstract;
|
||||
virtual int32_t ShowMenuDialog(
|
||||
const std::vector<std::string>& options, const std::string& title, const std::string& text) abstract;
|
||||
virtual void OpenFolder(const std::string& path) abstract;
|
||||
|
||||
virtual void OpenURL(const std::string& url) abstract;
|
||||
virtual std::string ShowFileDialog(SDL_Window* window, const FileDialogDesc& desc) abstract;
|
||||
virtual std::string ShowDirectoryDialog(SDL_Window* window, const std::string& title) abstract;
|
||||
|
||||
virtual bool HasFilePicker() const abstract;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::unique_ptr<IUiContext> CreateUiContext(const std::shared_ptr<IPlatformEnvironment>& env);
|
||||
[[nodiscard]] std::unique_ptr<IPlatformUiContext> CreatePlatformUiContext();
|
||||
|
||||
[[nodiscard]] InGameConsole& GetInGameConsole();
|
||||
} // namespace Ui
|
||||
} // namespace OpenRCT2
|
||||
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
struct FileDialogDesc;
|
||||
class InGameConsole;
|
||||
struct IUiContext;
|
||||
|
||||
struct IPlatformUiContext
|
||||
{
|
||||
virtual ~IPlatformUiContext() = default;
|
||||
virtual void SetWindowIcon(SDL_Window* window) abstract;
|
||||
virtual bool IsSteamOverlayAttached() abstract;
|
||||
|
||||
virtual void ShowMessageBox(SDL_Window* window, const std::string& message) abstract;
|
||||
virtual bool HasMenuSupport() abstract;
|
||||
virtual int32_t ShowMenuDialog(
|
||||
const std::vector<std::string>& options, const std::string& title, const std::string& text) abstract;
|
||||
virtual void OpenFolder(const std::string& path) abstract;
|
||||
|
||||
virtual void OpenURL(const std::string& url) abstract;
|
||||
virtual std::string ShowFileDialog(SDL_Window* window, const FileDialogDesc& desc) abstract;
|
||||
virtual std::string ShowDirectoryDialog(SDL_Window* window, const std::string& title) abstract;
|
||||
|
||||
virtual bool HasFilePicker() const abstract;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::unique_ptr<IUiContext> CreateUiContext(const std::shared_ptr<IPlatformEnvironment>& env);
|
||||
[[nodiscard]] std::unique_ptr<IPlatformUiContext> CreatePlatformUiContext();
|
||||
|
||||
[[nodiscard]] InGameConsole& GetInGameConsole();
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace OpenRCT2::Audio
|
|||
{
|
||||
if (SDL_Init(SDL_INIT_AUDIO) < 0)
|
||||
{
|
||||
SDLException::Throw("SDL_Init(SDL_INIT_AUDIO)");
|
||||
Ui::SDLException::Throw("SDL_Init(SDL_INIT_AUDIO)");
|
||||
}
|
||||
_audioMixer = std::make_unique<AudioMixer>();
|
||||
}
|
||||
|
|
|
@ -15,90 +15,93 @@
|
|||
#include <openrct2/core/Imaging.h>
|
||||
#include <stdexcept>
|
||||
|
||||
static std::vector<uint8_t> ReadToVector(std::istream& stream)
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
std::vector<uint8_t> result;
|
||||
if (!stream.eof() && !stream.fail())
|
||||
static std::vector<uint8_t> ReadToVector(std::istream& stream)
|
||||
{
|
||||
stream.seekg(0, std::ios_base::end);
|
||||
auto size = stream.tellg();
|
||||
result.resize(size);
|
||||
stream.seekg(0, std::ios_base::beg);
|
||||
stream.read(reinterpret_cast<char*>(result.data()), size);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO Bitmaps aren't very complicated to read so we should probably just write our
|
||||
// own implementation in libopenrct2 and spare the AOT implementation registration.
|
||||
static Image ReadBitmap(std::istream& istream, IMAGE_FORMAT format)
|
||||
{
|
||||
auto buffer = ReadToVector(istream);
|
||||
auto sdlStream = SDL_RWFromConstMem(buffer.data(), static_cast<int>(buffer.size()));
|
||||
auto bitmap = SDL_LoadBMP_RW(sdlStream, 1);
|
||||
if (bitmap != nullptr)
|
||||
{
|
||||
auto numChannels = bitmap->format->BytesPerPixel;
|
||||
if (numChannels < 3 || bitmap->format->BitsPerPixel < 24)
|
||||
std::vector<uint8_t> result;
|
||||
if (!stream.eof() && !stream.fail())
|
||||
{
|
||||
SDL_FreeSurface(bitmap);
|
||||
throw std::runtime_error("Only 24-bit bitmaps are supported.");
|
||||
stream.seekg(0, std::ios_base::end);
|
||||
auto size = stream.tellg();
|
||||
result.resize(size);
|
||||
stream.seekg(0, std::ios_base::beg);
|
||||
stream.read(reinterpret_cast<char*>(result.data()), size);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Copy pixels over, then discard the surface
|
||||
if (SDL_LockSurface(bitmap) == 0)
|
||||
// TODO Bitmaps aren't very complicated to read so we should probably just write our
|
||||
// own implementation in libopenrct2 and spare the AOT implementation registration.
|
||||
static Image ReadBitmap(std::istream& istream, IMAGE_FORMAT format)
|
||||
{
|
||||
auto buffer = ReadToVector(istream);
|
||||
auto sdlStream = SDL_RWFromConstMem(buffer.data(), static_cast<int>(buffer.size()));
|
||||
auto bitmap = SDL_LoadBMP_RW(sdlStream, 1);
|
||||
if (bitmap != nullptr)
|
||||
{
|
||||
Image image;
|
||||
image.Width = bitmap->w;
|
||||
image.Height = bitmap->h;
|
||||
image.Depth = 32;
|
||||
image.Pixels.resize(bitmap->w * bitmap->h * 4);
|
||||
image.Stride = bitmap->w * 4;
|
||||
|
||||
// Clear image with 0xFF
|
||||
std::fill(image.Pixels.begin(), image.Pixels.end(), 0xFF);
|
||||
|
||||
// Copy pixels over
|
||||
auto src = static_cast<const uint8_t*>(bitmap->pixels);
|
||||
auto dst = image.Pixels.data();
|
||||
if (numChannels == 4)
|
||||
auto numChannels = bitmap->format->BytesPerPixel;
|
||||
if (numChannels < 3 || bitmap->format->BitsPerPixel < 24)
|
||||
{
|
||||
for (int32_t y = 0; y < bitmap->h; y++)
|
||||
{
|
||||
std::memcpy(dst, src, bitmap->w);
|
||||
src += bitmap->pitch;
|
||||
dst += bitmap->w;
|
||||
}
|
||||
SDL_FreeSurface(bitmap);
|
||||
throw std::runtime_error("Only 24-bit bitmaps are supported.");
|
||||
}
|
||||
else
|
||||
|
||||
// Copy pixels over, then discard the surface
|
||||
if (SDL_LockSurface(bitmap) == 0)
|
||||
{
|
||||
for (int32_t y = 0; y < bitmap->h; y++)
|
||||
Image image;
|
||||
image.Width = bitmap->w;
|
||||
image.Height = bitmap->h;
|
||||
image.Depth = 32;
|
||||
image.Pixels.resize(bitmap->w * bitmap->h * 4);
|
||||
image.Stride = bitmap->w * 4;
|
||||
|
||||
// Clear image with 0xFF
|
||||
std::fill(image.Pixels.begin(), image.Pixels.end(), 0xFF);
|
||||
|
||||
// Copy pixels over
|
||||
auto src = static_cast<const uint8_t*>(bitmap->pixels);
|
||||
auto dst = image.Pixels.data();
|
||||
if (numChannels == 4)
|
||||
{
|
||||
for (int32_t x = 0; x < bitmap->w; x++)
|
||||
for (int32_t y = 0; y < bitmap->h; y++)
|
||||
{
|
||||
std::memcpy(dst, src, 3);
|
||||
src += 3;
|
||||
dst += 4;
|
||||
std::memcpy(dst, src, bitmap->w);
|
||||
src += bitmap->pitch;
|
||||
dst += bitmap->w;
|
||||
}
|
||||
src += bitmap->pitch - (bitmap->w * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32_t y = 0; y < bitmap->h; y++)
|
||||
{
|
||||
for (int32_t x = 0; x < bitmap->w; x++)
|
||||
{
|
||||
std::memcpy(dst, src, 3);
|
||||
src += 3;
|
||||
dst += 4;
|
||||
}
|
||||
src += bitmap->pitch - (bitmap->w * 3);
|
||||
}
|
||||
}
|
||||
SDL_UnlockSurface(bitmap);
|
||||
SDL_FreeSurface(bitmap);
|
||||
|
||||
return image;
|
||||
}
|
||||
SDL_UnlockSurface(bitmap);
|
||||
|
||||
SDL_FreeSurface(bitmap);
|
||||
|
||||
return image;
|
||||
throw std::runtime_error("Unable to lock surface.");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
}
|
||||
|
||||
SDL_FreeSurface(bitmap);
|
||||
throw std::runtime_error("Unable to lock surface.");
|
||||
}
|
||||
else
|
||||
|
||||
void RegisterBitmapReader()
|
||||
{
|
||||
throw std::runtime_error(SDL_GetError());
|
||||
Imaging::SetReader(IMAGE_FORMAT::BITMAP, ReadBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterBitmapReader()
|
||||
{
|
||||
Imaging::SetReader(IMAGE_FORMAT::BITMAP, ReadBitmap);
|
||||
}
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -9,4 +9,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
void RegisterBitmapReader();
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
void RegisterBitmapReader();
|
||||
}
|
||||
|
|
|
@ -13,41 +13,38 @@
|
|||
#include <openrct2/common.h>
|
||||
#include <openrct2/drawing/IDrawingEngine.h>
|
||||
|
||||
namespace OpenRCT2
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
namespace Ui
|
||||
struct IUiContext;
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Drawing::IDrawingEngine> CreateSoftwareDrawingEngine(
|
||||
const std::shared_ptr<IUiContext>& uiContext);
|
||||
[[nodiscard]] std::unique_ptr<Drawing::IDrawingEngine> CreateHardwareDisplayDrawingEngine(
|
||||
const std::shared_ptr<IUiContext>& uiContext);
|
||||
#ifndef DISABLE_OPENGL
|
||||
[[nodiscard]] std::unique_ptr<Drawing::IDrawingEngine> CreateOpenGLDrawingEngine(
|
||||
const std::shared_ptr<IUiContext>& uiContext);
|
||||
#endif
|
||||
|
||||
class DrawingEngineFactory final : public Drawing::IDrawingEngineFactory
|
||||
{
|
||||
using namespace OpenRCT2::Drawing;
|
||||
|
||||
struct IUiContext;
|
||||
|
||||
[[nodiscard]] std::unique_ptr<IDrawingEngine> CreateSoftwareDrawingEngine(const std::shared_ptr<IUiContext>& uiContext);
|
||||
[[nodiscard]] std::unique_ptr<IDrawingEngine> CreateHardwareDisplayDrawingEngine(
|
||||
const std::shared_ptr<IUiContext>& uiContext);
|
||||
#ifndef DISABLE_OPENGL
|
||||
[[nodiscard]] std::unique_ptr<IDrawingEngine> CreateOpenGLDrawingEngine(const std::shared_ptr<IUiContext>& uiContext);
|
||||
#endif
|
||||
|
||||
class DrawingEngineFactory final : public IDrawingEngineFactory
|
||||
public:
|
||||
[[nodiscard]] std::unique_ptr<Drawing::IDrawingEngine> Create(
|
||||
DrawingEngine type, const std::shared_ptr<IUiContext>& uiContext) override
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] std::unique_ptr<IDrawingEngine> Create(
|
||||
DrawingEngine type, const std::shared_ptr<IUiContext>& uiContext) override
|
||||
switch (type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DrawingEngine::Software:
|
||||
return CreateSoftwareDrawingEngine(uiContext);
|
||||
case DrawingEngine::SoftwareWithHardwareDisplay:
|
||||
return CreateHardwareDisplayDrawingEngine(uiContext);
|
||||
case DrawingEngine::Software:
|
||||
return CreateSoftwareDrawingEngine(uiContext);
|
||||
case DrawingEngine::SoftwareWithHardwareDisplay:
|
||||
return CreateHardwareDisplayDrawingEngine(uiContext);
|
||||
#ifndef DISABLE_OPENGL
|
||||
case DrawingEngine::OpenGL:
|
||||
return CreateOpenGLDrawingEngine(uiContext);
|
||||
case DrawingEngine::OpenGL:
|
||||
return CreateOpenGLDrawingEngine(uiContext);
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
} // namespace Ui
|
||||
} // namespace OpenRCT2
|
||||
}
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
# include "ApplyPaletteShader.h"
|
||||
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct VDStruct
|
||||
|
|
|
@ -12,27 +12,30 @@
|
|||
#include "GLSLTypes.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
|
||||
class ApplyPaletteShader final : public OpenGLShaderProgram
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
private:
|
||||
GLuint uTexture;
|
||||
GLuint uPalette;
|
||||
class ApplyPaletteShader final : public OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLuint uTexture;
|
||||
GLuint uPalette;
|
||||
|
||||
GLuint vPosition;
|
||||
GLuint vTextureCoordinate;
|
||||
GLuint vPosition;
|
||||
GLuint vTextureCoordinate;
|
||||
|
||||
GLuint _vbo;
|
||||
GLuint _vao;
|
||||
GLuint _vbo;
|
||||
GLuint _vao;
|
||||
|
||||
public:
|
||||
ApplyPaletteShader();
|
||||
~ApplyPaletteShader() override;
|
||||
public:
|
||||
ApplyPaletteShader();
|
||||
~ApplyPaletteShader() override;
|
||||
|
||||
static void SetTexture(GLuint texture);
|
||||
void SetPalette(const vec4* glPalette);
|
||||
static void SetTexture(GLuint texture);
|
||||
void SetPalette(const vec4* glPalette);
|
||||
|
||||
void Draw();
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
# include "ApplyTransparencyShader.h"
|
||||
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct VDStruct
|
||||
|
|
|
@ -11,32 +11,34 @@
|
|||
|
||||
#include "GLSLTypes.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
|
||||
class ApplyTransparencyShader final : public OpenGLShaderProgram
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
private:
|
||||
GLuint uOpaqueTex;
|
||||
GLuint uOpaqueDepth;
|
||||
GLuint uTransparentTex;
|
||||
GLuint uTransparentDepth;
|
||||
GLuint uPaletteTex;
|
||||
GLuint uBlendPaletteTex;
|
||||
class ApplyTransparencyShader final : public OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLuint uOpaqueTex;
|
||||
GLuint uOpaqueDepth;
|
||||
GLuint uTransparentTex;
|
||||
GLuint uTransparentDepth;
|
||||
GLuint uPaletteTex;
|
||||
GLuint uBlendPaletteTex;
|
||||
|
||||
GLuint vPosition;
|
||||
GLuint vTextureCoordinate;
|
||||
GLuint vPosition;
|
||||
GLuint vTextureCoordinate;
|
||||
|
||||
GLuint _vbo;
|
||||
GLuint _vao;
|
||||
GLuint _vbo;
|
||||
GLuint _vao;
|
||||
|
||||
public:
|
||||
ApplyTransparencyShader();
|
||||
~ApplyTransparencyShader() override;
|
||||
public:
|
||||
ApplyTransparencyShader();
|
||||
~ApplyTransparencyShader() override;
|
||||
|
||||
static void SetTextures(
|
||||
GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex,
|
||||
GLuint blendPaletteTex);
|
||||
void Draw();
|
||||
static void SetTextures(
|
||||
GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex,
|
||||
GLuint blendPaletteTex);
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -15,114 +15,116 @@
|
|||
|
||||
#include <openrct2/common.h>
|
||||
#include <vector>
|
||||
|
||||
template<typename T> class CommandBatch
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
private:
|
||||
std::vector<T> _instances;
|
||||
size_t _numInstances;
|
||||
template<typename T> class CommandBatch
|
||||
{
|
||||
private:
|
||||
std::vector<T> _instances;
|
||||
size_t _numInstances;
|
||||
|
||||
public:
|
||||
CommandBatch()
|
||||
: _numInstances(0)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _numInstances == 0;
|
||||
}
|
||||
void clear() // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
_numInstances = 0;
|
||||
}
|
||||
T& allocate() // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
if (_numInstances + 1 > _instances.size())
|
||||
public:
|
||||
CommandBatch()
|
||||
: _numInstances(0)
|
||||
{
|
||||
_instances.resize((_numInstances + 1) << 1);
|
||||
}
|
||||
return _instances[_numInstances++];
|
||||
}
|
||||
T& insert(const T& value) // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
if (_numInstances + 1 > _instances.size())
|
||||
|
||||
[[nodiscard]] bool empty() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
_instances.resize((_numInstances + 1) << 1);
|
||||
return _numInstances == 0;
|
||||
}
|
||||
void clear() // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
_numInstances = 0;
|
||||
}
|
||||
T& allocate() // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
if (_numInstances + 1 > _instances.size())
|
||||
{
|
||||
_instances.resize((_numInstances + 1) << 1);
|
||||
}
|
||||
return _instances[_numInstances++];
|
||||
}
|
||||
T& insert(const T& value) // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
if (_numInstances + 1 > _instances.size())
|
||||
{
|
||||
_instances.resize((_numInstances + 1) << 1);
|
||||
}
|
||||
return _instances[_numInstances++] = value;
|
||||
}
|
||||
[[nodiscard]] size_t size() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _numInstances;
|
||||
}
|
||||
const T* data() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.data();
|
||||
}
|
||||
const T& operator[](size_t idx) const
|
||||
{
|
||||
return _instances.at(idx);
|
||||
}
|
||||
return _instances[_numInstances++] = value;
|
||||
}
|
||||
[[nodiscard]] size_t size() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _numInstances;
|
||||
}
|
||||
const T* data() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.data();
|
||||
}
|
||||
const T& operator[](size_t idx) const
|
||||
{
|
||||
return _instances.at(idx);
|
||||
}
|
||||
|
||||
typename std::vector<T>::iterator begin() // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.begin();
|
||||
}
|
||||
typename std::vector<T>::const_iterator begin() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.cbegin();
|
||||
}
|
||||
typename std::vector<T>::const_iterator cbegin() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.cbegin();
|
||||
}
|
||||
typename std::vector<T>::iterator end() // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.begin() + _numInstances;
|
||||
}
|
||||
typename std::vector<T>::const_iterator end() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.cbegin() + _numInstances;
|
||||
}
|
||||
typename std::vector<T>::const_iterator cend() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.cbegin() + _numInstances;
|
||||
}
|
||||
};
|
||||
|
||||
struct DrawLineCommand
|
||||
{
|
||||
ivec4 clip;
|
||||
ivec4 bounds;
|
||||
GLuint colour;
|
||||
GLint depth;
|
||||
};
|
||||
|
||||
// Per-instance data for images
|
||||
struct DrawRectCommand
|
||||
{
|
||||
ivec4 clip;
|
||||
GLint texColourAtlas;
|
||||
vec4 texColourBounds;
|
||||
GLint texMaskAtlas;
|
||||
vec4 texMaskBounds;
|
||||
ivec3 palettes;
|
||||
GLint flags;
|
||||
GLuint colour;
|
||||
ivec4 bounds;
|
||||
GLint depth;
|
||||
|
||||
enum
|
||||
{
|
||||
FLAG_NO_TEXTURE = (1u << 2u),
|
||||
FLAG_MASK = (1u << 3u),
|
||||
FLAG_CROSS_HATCH = (1u << 4u),
|
||||
FLAG_TTF_TEXT = (1u << 5u),
|
||||
// bits 8 to 16 used to store hinting threshold.
|
||||
FLAG_TTF_HINTING_THRESHOLD_MASK = 0xff00
|
||||
typename std::vector<T>::iterator begin() // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.begin();
|
||||
}
|
||||
typename std::vector<T>::const_iterator begin() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.cbegin();
|
||||
}
|
||||
typename std::vector<T>::const_iterator cbegin() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.cbegin();
|
||||
}
|
||||
typename std::vector<T>::iterator end() // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.begin() + _numInstances;
|
||||
}
|
||||
typename std::vector<T>::const_iterator end() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.cbegin() + _numInstances;
|
||||
}
|
||||
typename std::vector<T>::const_iterator cend() const // NOLINT(readability-identifier-naming)
|
||||
{
|
||||
return _instances.cbegin() + _numInstances;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
using LineCommandBatch = CommandBatch<DrawLineCommand>;
|
||||
using RectCommandBatch = CommandBatch<DrawRectCommand>;
|
||||
struct DrawLineCommand
|
||||
{
|
||||
ivec4 clip;
|
||||
ivec4 bounds;
|
||||
GLuint colour;
|
||||
GLint depth;
|
||||
};
|
||||
|
||||
// Per-instance data for images
|
||||
struct DrawRectCommand
|
||||
{
|
||||
ivec4 clip;
|
||||
GLint texColourAtlas;
|
||||
vec4 texColourBounds;
|
||||
GLint texMaskAtlas;
|
||||
vec4 texMaskBounds;
|
||||
ivec3 palettes;
|
||||
GLint flags;
|
||||
GLuint colour;
|
||||
ivec4 bounds;
|
||||
GLint depth;
|
||||
|
||||
enum
|
||||
{
|
||||
FLAG_NO_TEXTURE = (1u << 2u),
|
||||
FLAG_MASK = (1u << 3u),
|
||||
FLAG_CROSS_HATCH = (1u << 4u),
|
||||
FLAG_TTF_TEXT = (1u << 5u),
|
||||
// bits 8 to 16 used to store hinting threshold.
|
||||
FLAG_TTF_HINTING_THRESHOLD_MASK = 0xff00
|
||||
};
|
||||
};
|
||||
|
||||
using LineCommandBatch = CommandBatch<DrawLineCommand>;
|
||||
using RectCommandBatch = CommandBatch<DrawRectCommand>;
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
# include "OpenGLFramebuffer.h"
|
||||
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct VDStruct
|
||||
|
|
|
@ -12,30 +12,32 @@
|
|||
#include "DrawCommands.h"
|
||||
#include "GLSLTypes.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
|
||||
class DrawLineShader final : public OpenGLShaderProgram
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
private:
|
||||
GLuint uScreenSize;
|
||||
class DrawLineShader final : public OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLuint uScreenSize;
|
||||
|
||||
GLuint vClip;
|
||||
GLuint vBounds;
|
||||
GLuint vColour;
|
||||
GLuint vDepth;
|
||||
GLuint vClip;
|
||||
GLuint vBounds;
|
||||
GLuint vColour;
|
||||
GLuint vDepth;
|
||||
|
||||
GLuint vVertMat;
|
||||
GLuint vVertMat;
|
||||
|
||||
GLuint _vbo;
|
||||
GLuint _vboInstances;
|
||||
GLuint _vao;
|
||||
GLuint _vbo;
|
||||
GLuint _vboInstances;
|
||||
GLuint _vao;
|
||||
|
||||
public:
|
||||
DrawLineShader();
|
||||
~DrawLineShader() override;
|
||||
public:
|
||||
DrawLineShader();
|
||||
~DrawLineShader() override;
|
||||
|
||||
void SetScreenSize(int32_t width, int32_t height);
|
||||
void DrawInstances(const LineCommandBatch& instances);
|
||||
void SetScreenSize(int32_t width, int32_t height);
|
||||
void DrawInstances(const LineCommandBatch& instances);
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
# include "DrawRectShader.h"
|
||||
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct VDStruct
|
||||
|
|
|
@ -14,49 +14,51 @@
|
|||
#include "OpenGLShaderProgram.h"
|
||||
|
||||
#include <SDL_pixels.h>
|
||||
|
||||
class DrawRectShader final : public OpenGLShaderProgram
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
private:
|
||||
GLuint uScreenSize;
|
||||
GLuint uTexture;
|
||||
GLuint uPaletteTex;
|
||||
class DrawRectShader final : public OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLuint uScreenSize;
|
||||
GLuint uTexture;
|
||||
GLuint uPaletteTex;
|
||||
|
||||
GLuint uPeelingTex;
|
||||
GLuint uPeeling;
|
||||
GLuint uPeelingTex;
|
||||
GLuint uPeeling;
|
||||
|
||||
GLuint vVertMat;
|
||||
GLuint vVertVec;
|
||||
GLuint vVertMat;
|
||||
GLuint vVertVec;
|
||||
|
||||
GLuint vClip;
|
||||
GLuint vTexColourAtlas;
|
||||
GLuint vTexColourBounds;
|
||||
GLuint vTexMaskAtlas;
|
||||
GLuint vTexMaskBounds;
|
||||
GLuint vPalettes;
|
||||
GLuint vFlags;
|
||||
GLuint vColour;
|
||||
GLuint vBounds;
|
||||
GLuint vDepth;
|
||||
GLuint vClip;
|
||||
GLuint vTexColourAtlas;
|
||||
GLuint vTexColourBounds;
|
||||
GLuint vTexMaskAtlas;
|
||||
GLuint vTexMaskBounds;
|
||||
GLuint vPalettes;
|
||||
GLuint vFlags;
|
||||
GLuint vColour;
|
||||
GLuint vBounds;
|
||||
GLuint vDepth;
|
||||
|
||||
GLuint _vbo;
|
||||
GLuint _vboInstances;
|
||||
GLuint _vao;
|
||||
GLuint _vbo;
|
||||
GLuint _vboInstances;
|
||||
GLuint _vao;
|
||||
|
||||
GLsizei _instanceCount = 0;
|
||||
size_t _maxInstancesBufferSize;
|
||||
GLsizei _instanceCount = 0;
|
||||
size_t _maxInstancesBufferSize;
|
||||
|
||||
public:
|
||||
DrawRectShader();
|
||||
~DrawRectShader() override;
|
||||
public:
|
||||
DrawRectShader();
|
||||
~DrawRectShader() override;
|
||||
|
||||
void SetScreenSize(int32_t width, int32_t height);
|
||||
void EnablePeeling(GLuint peelingTex);
|
||||
void DisablePeeling();
|
||||
void SetScreenSize(int32_t width, int32_t height);
|
||||
void EnablePeeling(GLuint peelingTex);
|
||||
void DisablePeeling();
|
||||
|
||||
void SetInstances(const RectCommandBatch& instances);
|
||||
void DrawInstances();
|
||||
void SetInstances(const RectCommandBatch& instances);
|
||||
void DrawInstances();
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -13,100 +13,102 @@
|
|||
|
||||
#include <openrct2/common.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
namespace detail
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
template<typename T_> struct Vec2
|
||||
#pragma pack(push, 1)
|
||||
namespace detail
|
||||
{
|
||||
using ValueType = T_;
|
||||
|
||||
union
|
||||
template<typename T_> struct Vec2
|
||||
{
|
||||
ValueType x;
|
||||
ValueType s;
|
||||
ValueType r;
|
||||
using ValueType = T_;
|
||||
|
||||
union
|
||||
{
|
||||
ValueType x;
|
||||
ValueType s;
|
||||
ValueType r;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType y;
|
||||
ValueType t;
|
||||
ValueType g;
|
||||
};
|
||||
};
|
||||
union
|
||||
|
||||
template struct Vec2<GLfloat>;
|
||||
template struct Vec2<GLint>;
|
||||
|
||||
template<typename T_> struct Vec3
|
||||
{
|
||||
ValueType y;
|
||||
ValueType t;
|
||||
ValueType g;
|
||||
using ValueType = T_;
|
||||
|
||||
union
|
||||
{
|
||||
ValueType x;
|
||||
ValueType s;
|
||||
ValueType r;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType y;
|
||||
ValueType t;
|
||||
ValueType g;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType z;
|
||||
ValueType p;
|
||||
ValueType b;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
template struct Vec2<GLfloat>;
|
||||
template struct Vec2<GLint>;
|
||||
template struct Vec3<GLfloat>;
|
||||
template struct Vec3<GLint>;
|
||||
|
||||
template<typename T_> struct Vec3
|
||||
{
|
||||
using ValueType = T_;
|
||||
|
||||
union
|
||||
template<typename T_> struct Vec4
|
||||
{
|
||||
ValueType x;
|
||||
ValueType s;
|
||||
ValueType r;
|
||||
using ValueType = T_;
|
||||
|
||||
union
|
||||
{
|
||||
ValueType x;
|
||||
ValueType s;
|
||||
ValueType r;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType y;
|
||||
ValueType t;
|
||||
ValueType g;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType z;
|
||||
ValueType p;
|
||||
ValueType b;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType w;
|
||||
ValueType q;
|
||||
ValueType a;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType y;
|
||||
ValueType t;
|
||||
ValueType g;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType z;
|
||||
ValueType p;
|
||||
ValueType b;
|
||||
};
|
||||
};
|
||||
|
||||
template struct Vec3<GLfloat>;
|
||||
template struct Vec3<GLint>;
|
||||
template struct Vec4<GLfloat>;
|
||||
template struct Vec4<GLint>;
|
||||
|
||||
template<typename T_> struct Vec4
|
||||
{
|
||||
using ValueType = T_;
|
||||
} // namespace detail
|
||||
|
||||
union
|
||||
{
|
||||
ValueType x;
|
||||
ValueType s;
|
||||
ValueType r;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType y;
|
||||
ValueType t;
|
||||
ValueType g;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType z;
|
||||
ValueType p;
|
||||
ValueType b;
|
||||
};
|
||||
union
|
||||
{
|
||||
ValueType w;
|
||||
ValueType q;
|
||||
ValueType a;
|
||||
};
|
||||
};
|
||||
using vec2 = detail::Vec2<GLfloat>;
|
||||
using ivec2 = detail::Vec2<GLint>;
|
||||
|
||||
template struct Vec4<GLfloat>;
|
||||
template struct Vec4<GLint>;
|
||||
using vec3 = detail::Vec3<GLfloat>;
|
||||
using ivec3 = detail::Vec3<GLint>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using vec2 = detail::Vec2<GLfloat>;
|
||||
using ivec2 = detail::Vec2<GLint>;
|
||||
|
||||
using vec3 = detail::Vec3<GLfloat>;
|
||||
using ivec3 = detail::Vec3<GLint>;
|
||||
|
||||
using vec4 = detail::Vec4<GLfloat>;
|
||||
using ivec4 = detail::Vec4<GLint>;
|
||||
using vec4 = detail::Vec4<GLfloat>;
|
||||
using ivec4 = detail::Vec4<GLint>;
|
||||
|
||||
#pragma pack(pop)
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -38,7 +38,9 @@ static const char* TryLoadAllProcAddresses()
|
|||
|
||||
# endif /* #if OPENGL_NO_LINK */
|
||||
|
||||
namespace OpenGLState
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
namespace OpenRCT2::Ui::OpenGLState
|
||||
{
|
||||
uint16_t ActiveTexture;
|
||||
GLuint CurrentProgram;
|
||||
|
@ -48,7 +50,7 @@ namespace OpenGLState
|
|||
ActiveTexture = UINT16_MAX;
|
||||
CurrentProgram = UINT32_MAX;
|
||||
}
|
||||
} // namespace OpenGLState
|
||||
} // namespace OpenRCT2::Ui::OpenGLState
|
||||
|
||||
void OpenGLAPI::SetTexture(uint16_t index, GLenum type, GLuint texture)
|
||||
{
|
||||
|
|
|
@ -113,26 +113,29 @@ using PFNGLGETTEXIMAGEPROC = void(APIENTRYP)(GLenum target, GLint level, GLenum
|
|||
|
||||
#endif /* OPENGL_NO_LINK */
|
||||
|
||||
inline void CheckGLError()
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
GLenum error = glGetError();
|
||||
while (error != GL_NO_ERROR)
|
||||
inline void CheckGLError()
|
||||
{
|
||||
LOG_ERROR("OpenGL Error 0x%04X", error);
|
||||
error = glGetError();
|
||||
GLenum error = glGetError();
|
||||
while (error != GL_NO_ERROR)
|
||||
{
|
||||
LOG_ERROR("OpenGL Error 0x%04X", error);
|
||||
error = glGetError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace OpenGLAPI
|
||||
{
|
||||
bool Initialise();
|
||||
void SetTexture(uint16_t index, GLenum type, GLuint texture);
|
||||
} // namespace OpenGLAPI
|
||||
namespace OpenGLAPI
|
||||
{
|
||||
bool Initialise();
|
||||
void SetTexture(uint16_t index, GLenum type, GLuint texture);
|
||||
} // namespace OpenGLAPI
|
||||
|
||||
namespace OpenGLState
|
||||
{
|
||||
extern uint16_t ActiveTexture;
|
||||
extern GLuint CurrentProgram;
|
||||
namespace OpenGLState
|
||||
{
|
||||
extern uint16_t ActiveTexture;
|
||||
extern GLuint CurrentProgram;
|
||||
|
||||
void Reset();
|
||||
} // namespace OpenGLState
|
||||
void Reset();
|
||||
} // namespace OpenGLState
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
# include <memory>
|
||||
# include <openrct2/common.h>
|
||||
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
constexpr GLuint BACKBUFFER_ID = 0;
|
||||
|
||||
OpenGLFramebuffer::OpenGLFramebuffer(SDL_Window* window)
|
||||
|
|
|
@ -16,49 +16,51 @@
|
|||
#include <vector>
|
||||
|
||||
struct SDL_Window;
|
||||
|
||||
class OpenGLFramebuffer
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
private:
|
||||
GLuint _id;
|
||||
GLuint _texture;
|
||||
GLuint _depth;
|
||||
int32_t _width;
|
||||
int32_t _height;
|
||||
|
||||
public:
|
||||
explicit OpenGLFramebuffer(SDL_Window* window);
|
||||
OpenGLFramebuffer(int32_t width, int32_t height, bool depth = true, bool integer = true, bool word = false);
|
||||
~OpenGLFramebuffer();
|
||||
|
||||
OpenGLFramebuffer(const OpenGLFramebuffer&) = delete;
|
||||
OpenGLFramebuffer& operator=(const OpenGLFramebuffer&) = delete;
|
||||
|
||||
GLuint GetWidth() const
|
||||
class OpenGLFramebuffer
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
GLuint GetHeight() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
GLuint GetTexture() const
|
||||
{
|
||||
return _texture;
|
||||
}
|
||||
GLuint GetDepthTexture() const
|
||||
{
|
||||
return _depth;
|
||||
}
|
||||
private:
|
||||
GLuint _id;
|
||||
GLuint _texture;
|
||||
GLuint _depth;
|
||||
int32_t _width;
|
||||
int32_t _height;
|
||||
|
||||
void Bind() const;
|
||||
void BindDraw() const;
|
||||
void BindRead() const;
|
||||
void GetPixels(DrawPixelInfo& dpi) const;
|
||||
public:
|
||||
explicit OpenGLFramebuffer(SDL_Window* window);
|
||||
OpenGLFramebuffer(int32_t width, int32_t height, bool depth = true, bool integer = true, bool word = false);
|
||||
~OpenGLFramebuffer();
|
||||
|
||||
void SwapColourBuffer(OpenGLFramebuffer& other);
|
||||
GLuint SwapDepthTexture(GLuint depth);
|
||||
void Copy(OpenGLFramebuffer& src, GLenum filter);
|
||||
OpenGLFramebuffer(const OpenGLFramebuffer&) = delete;
|
||||
OpenGLFramebuffer& operator=(const OpenGLFramebuffer&) = delete;
|
||||
|
||||
static GLuint CreateDepthTexture(int32_t width, int32_t height);
|
||||
};
|
||||
GLuint GetWidth() const
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
GLuint GetHeight() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
GLuint GetTexture() const
|
||||
{
|
||||
return _texture;
|
||||
}
|
||||
GLuint GetDepthTexture() const
|
||||
{
|
||||
return _depth;
|
||||
}
|
||||
|
||||
void Bind() const;
|
||||
void BindDraw() const;
|
||||
void BindRead() const;
|
||||
void GetPixels(DrawPixelInfo& dpi) const;
|
||||
|
||||
void SwapColourBuffer(OpenGLFramebuffer& other);
|
||||
GLuint SwapDepthTexture(GLuint depth);
|
||||
void Copy(OpenGLFramebuffer& src, GLenum filter);
|
||||
|
||||
static GLuint CreateDepthTexture(int32_t width, int32_t height);
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# include <openrct2/core/Path.hpp>
|
||||
# include <openrct2/core/String.hpp>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
OpenGLShader::OpenGLShader(const char* name, GLenum type)
|
||||
: _type(type)
|
||||
|
|
|
@ -14,43 +14,45 @@
|
|||
#include <memory>
|
||||
#include <openrct2/common.h>
|
||||
#include <string>
|
||||
|
||||
class OpenGLShader final
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
private:
|
||||
static constexpr uint64_t MaxSourceSize = 8 * 1024 * 1024; // 8 MiB
|
||||
class OpenGLShader final
|
||||
{
|
||||
private:
|
||||
static constexpr uint64_t MaxSourceSize = 8 * 1024 * 1024; // 8 MiB
|
||||
|
||||
GLenum _type;
|
||||
GLuint _id = 0;
|
||||
GLenum _type;
|
||||
GLuint _id = 0;
|
||||
|
||||
public:
|
||||
OpenGLShader(const char* name, GLenum type);
|
||||
~OpenGLShader();
|
||||
public:
|
||||
OpenGLShader(const char* name, GLenum type);
|
||||
~OpenGLShader();
|
||||
|
||||
GLuint GetShaderId();
|
||||
GLuint GetShaderId();
|
||||
|
||||
private:
|
||||
std::string GetPath(const std::string& name);
|
||||
static std::string ReadSourceCode(const std::string& path);
|
||||
};
|
||||
private:
|
||||
std::string GetPath(const std::string& name);
|
||||
static std::string ReadSourceCode(const std::string& path);
|
||||
};
|
||||
|
||||
class OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLuint _id = 0;
|
||||
std::unique_ptr<OpenGLShader> _vertexShader;
|
||||
std::unique_ptr<OpenGLShader> _fragmentShader;
|
||||
class OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLuint _id = 0;
|
||||
std::unique_ptr<OpenGLShader> _vertexShader;
|
||||
std::unique_ptr<OpenGLShader> _fragmentShader;
|
||||
|
||||
public:
|
||||
explicit OpenGLShaderProgram(const char* name);
|
||||
explicit OpenGLShaderProgram(const OpenGLShaderProgram&) = delete;
|
||||
explicit OpenGLShaderProgram(OpenGLShaderProgram&&) = default;
|
||||
virtual ~OpenGLShaderProgram();
|
||||
public:
|
||||
explicit OpenGLShaderProgram(const char* name);
|
||||
explicit OpenGLShaderProgram(const OpenGLShaderProgram&) = delete;
|
||||
explicit OpenGLShaderProgram(OpenGLShaderProgram&&) = default;
|
||||
virtual ~OpenGLShaderProgram();
|
||||
|
||||
GLuint GetAttributeLocation(const char* name);
|
||||
GLuint GetUniformLocation(const char* name);
|
||||
void Use();
|
||||
GLuint GetAttributeLocation(const char* name);
|
||||
GLuint GetUniformLocation(const char* name);
|
||||
void Use();
|
||||
|
||||
private:
|
||||
bool Link();
|
||||
};
|
||||
private:
|
||||
bool Link();
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
# include "OpenGLFramebuffer.h"
|
||||
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
constexpr GLfloat depthValue[1] = { 1.0f };
|
||||
constexpr GLfloat depthValueTransparent[1] = { 0.0f };
|
||||
constexpr GLuint indexValue[4] = { 0, 0, 0, 0 };
|
||||
|
|
|
@ -14,44 +14,46 @@
|
|||
#include "OpenGLFramebuffer.h"
|
||||
|
||||
#include <openrct2/common.h>
|
||||
|
||||
/**
|
||||
* Class to maintain two different framebuffers where the active framebuffer
|
||||
* will swap between the two, copying the other's pixels in the process for
|
||||
* performing pre-processing filters.
|
||||
*
|
||||
* When you need to bind the current frame to a shader, call SwapCopy and
|
||||
* then bind the value of GetSourceTexture to your shader.
|
||||
*/
|
||||
class SwapFramebuffer final
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
private:
|
||||
OpenGLFramebuffer _opaqueFramebuffer;
|
||||
OpenGLFramebuffer _transparentFramebuffer;
|
||||
OpenGLFramebuffer _mixFramebuffer;
|
||||
GLuint _backDepth;
|
||||
/**
|
||||
* Class to maintain two different framebuffers where the active framebuffer
|
||||
* will swap between the two, copying the other's pixels in the process for
|
||||
* performing pre-processing filters.
|
||||
*
|
||||
* When you need to bind the current frame to a shader, call SwapCopy and
|
||||
* then bind the value of GetSourceTexture to your shader.
|
||||
*/
|
||||
class SwapFramebuffer final
|
||||
{
|
||||
private:
|
||||
OpenGLFramebuffer _opaqueFramebuffer;
|
||||
OpenGLFramebuffer _transparentFramebuffer;
|
||||
OpenGLFramebuffer _mixFramebuffer;
|
||||
GLuint _backDepth;
|
||||
|
||||
public:
|
||||
SwapFramebuffer(int32_t width, int32_t height);
|
||||
~SwapFramebuffer();
|
||||
public:
|
||||
SwapFramebuffer(int32_t width, int32_t height);
|
||||
~SwapFramebuffer();
|
||||
|
||||
const OpenGLFramebuffer& GetFinalFramebuffer() const
|
||||
{
|
||||
return _opaqueFramebuffer;
|
||||
}
|
||||
GLuint GetBackDepthTexture() const
|
||||
{
|
||||
return _backDepth;
|
||||
}
|
||||
void BindOpaque()
|
||||
{
|
||||
_opaqueFramebuffer.Bind();
|
||||
}
|
||||
void BindTransparent()
|
||||
{
|
||||
_transparentFramebuffer.Bind();
|
||||
}
|
||||
const OpenGLFramebuffer& GetFinalFramebuffer() const
|
||||
{
|
||||
return _opaqueFramebuffer;
|
||||
}
|
||||
GLuint GetBackDepthTexture() const
|
||||
{
|
||||
return _backDepth;
|
||||
}
|
||||
void BindOpaque()
|
||||
{
|
||||
_opaqueFramebuffer.Bind();
|
||||
}
|
||||
void BindTransparent()
|
||||
{
|
||||
_transparentFramebuffer.Bind();
|
||||
}
|
||||
|
||||
void ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex, GLuint blendPaletteTex);
|
||||
void Clear();
|
||||
};
|
||||
void ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex, GLuint blendPaletteTex);
|
||||
void Clear();
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
# include <stdexcept>
|
||||
# include <vector>
|
||||
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
constexpr uint32_t UNUSED_INDEX = 0xFFFFFFFF;
|
||||
|
||||
TextureCache::TextureCache()
|
||||
|
|
|
@ -29,220 +29,223 @@ struct DrawPixelInfo;
|
|||
struct PaletteMap;
|
||||
enum class FilterPaletteID : int32_t;
|
||||
|
||||
struct GlyphId
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
ImageIndex Image;
|
||||
uint64_t Palette;
|
||||
|
||||
struct Hash
|
||||
struct GlyphId
|
||||
{
|
||||
size_t operator()(const GlyphId& k) const
|
||||
ImageIndex Image;
|
||||
uint64_t Palette;
|
||||
|
||||
struct Hash
|
||||
{
|
||||
size_t hash = k.Image * 7;
|
||||
hash += (k.Palette & 0xFFFFFFFFUL) * 13;
|
||||
hash += (k.Palette >> 32uL) * 23;
|
||||
return hash;
|
||||
size_t operator()(const GlyphId& k) const
|
||||
{
|
||||
size_t hash = k.Image * 7;
|
||||
hash += (k.Palette & 0xFFFFFFFFUL) * 13;
|
||||
hash += (k.Palette >> 32uL) * 23;
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
struct Equal
|
||||
{
|
||||
bool operator()(const GlyphId& lhs, const GlyphId& rhs) const
|
||||
{
|
||||
return lhs.Image == rhs.Image && lhs.Palette == rhs.Palette;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// This is the maximum width and height of each atlas, basically the
|
||||
// granularity at which new atlases are allocated (2048 -> 4 MB of VRAM)
|
||||
constexpr int32_t TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048;
|
||||
|
||||
// Pixel dimensions of smallest supported slots in texture atlases
|
||||
// Must be a power of 2!
|
||||
constexpr int32_t TEXTURE_CACHE_SMALLEST_SLOT = 32;
|
||||
|
||||
struct BasicTextureInfo
|
||||
{
|
||||
GLuint index;
|
||||
vec4 normalizedBounds;
|
||||
};
|
||||
|
||||
// Location of an image (texture atlas index, slot and normalized coordinates)
|
||||
struct AtlasTextureInfo : public BasicTextureInfo
|
||||
{
|
||||
GLuint slot;
|
||||
ivec4 bounds;
|
||||
ImageIndex image;
|
||||
};
|
||||
|
||||
// Represents a texture atlas that images of a given maximum size can be allocated from
|
||||
// Atlases are all stored in the same 2D texture array, occupying the specified index
|
||||
// Slots in atlases are always squares.
|
||||
class Atlas final
|
||||
{
|
||||
private:
|
||||
GLuint _index = 0;
|
||||
int32_t _imageSize = 0;
|
||||
int32_t _atlasWidth = 0;
|
||||
int32_t _atlasHeight = 0;
|
||||
std::vector<GLuint> _freeSlots;
|
||||
|
||||
int32_t _cols = 0;
|
||||
int32_t _rows = 0;
|
||||
|
||||
public:
|
||||
Atlas(GLuint index, int32_t imageSize)
|
||||
: _index(index)
|
||||
, _imageSize(imageSize)
|
||||
{
|
||||
}
|
||||
|
||||
void Initialise(int32_t atlasWidth, int32_t atlasHeight)
|
||||
{
|
||||
_atlasWidth = atlasWidth;
|
||||
_atlasHeight = atlasHeight;
|
||||
|
||||
_cols = std::max(1, _atlasWidth / _imageSize);
|
||||
_rows = std::max(1, _atlasHeight / _imageSize);
|
||||
|
||||
_freeSlots.resize(_cols * _rows);
|
||||
for (size_t i = 0; i < _freeSlots.size(); i++)
|
||||
{
|
||||
_freeSlots[i] = static_cast<GLuint>(i);
|
||||
}
|
||||
}
|
||||
|
||||
AtlasTextureInfo Allocate(int32_t actualWidth, int32_t actualHeight)
|
||||
{
|
||||
assert(!_freeSlots.empty());
|
||||
|
||||
GLuint slot = _freeSlots.back();
|
||||
_freeSlots.pop_back();
|
||||
|
||||
auto bounds = GetSlotCoordinates(slot, actualWidth, actualHeight);
|
||||
|
||||
AtlasTextureInfo info{};
|
||||
info.index = _index;
|
||||
info.slot = slot;
|
||||
info.bounds = bounds;
|
||||
info.normalizedBounds = NormalizeCoordinates(bounds);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void Free(const AtlasTextureInfo& info)
|
||||
{
|
||||
assert(_index == info.index);
|
||||
|
||||
_freeSlots.push_back(info.slot);
|
||||
}
|
||||
|
||||
// Checks if specified image would be tightly packed in this atlas
|
||||
// by checking if it is within the right power of 2 range
|
||||
[[nodiscard]] bool IsImageSuitable(int32_t actualWidth, int32_t actualHeight) const
|
||||
{
|
||||
int32_t imageOrder = CalculateImageSizeOrder(actualWidth, actualHeight);
|
||||
int32_t atlasOrder = log2(_imageSize);
|
||||
|
||||
return imageOrder == atlasOrder;
|
||||
}
|
||||
|
||||
[[nodiscard]] int32_t GetFreeSlots() const
|
||||
{
|
||||
return static_cast<int32_t>(_freeSlots.size());
|
||||
}
|
||||
|
||||
static int32_t CalculateImageSizeOrder(int32_t actualWidth, int32_t actualHeight)
|
||||
{
|
||||
int32_t actualSize = std::max(actualWidth, actualHeight);
|
||||
|
||||
if (actualSize < TEXTURE_CACHE_SMALLEST_SLOT)
|
||||
{
|
||||
actualSize = TEXTURE_CACHE_SMALLEST_SLOT;
|
||||
}
|
||||
|
||||
return static_cast<int32_t>(ceil(log2f(static_cast<float>(actualSize))));
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] ivec4 GetSlotCoordinates(GLuint slot, int32_t actualWidth, int32_t actualHeight) const
|
||||
{
|
||||
int32_t row = slot / _cols;
|
||||
int32_t col = slot % _cols;
|
||||
|
||||
return ivec4{
|
||||
_imageSize * col,
|
||||
_imageSize * row,
|
||||
_imageSize * col + actualWidth,
|
||||
_imageSize * row + actualHeight,
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] vec4 NormalizeCoordinates(const ivec4& coords) const
|
||||
{
|
||||
return vec4{
|
||||
coords.x / static_cast<float>(_atlasWidth),
|
||||
coords.y / static_cast<float>(_atlasHeight),
|
||||
coords.z / static_cast<float>(_atlasWidth),
|
||||
coords.w / static_cast<float>(_atlasHeight),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct Equal
|
||||
class TextureCache final
|
||||
{
|
||||
bool operator()(const GlyphId& lhs, const GlyphId& rhs) const
|
||||
{
|
||||
return lhs.Image == rhs.Image && lhs.Palette == rhs.Palette;
|
||||
}
|
||||
};
|
||||
};
|
||||
private:
|
||||
bool _initialized = false;
|
||||
|
||||
// This is the maximum width and height of each atlas, basically the
|
||||
// granularity at which new atlases are allocated (2048 -> 4 MB of VRAM)
|
||||
constexpr int32_t TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048;
|
||||
GLuint _atlasesTexture = 0;
|
||||
GLint _atlasesTextureDimensions = 0;
|
||||
GLuint _atlasesTextureCapacity = 0;
|
||||
GLuint _atlasesTextureIndices = 0;
|
||||
GLint _atlasesTextureIndicesLimit = 0;
|
||||
std::vector<Atlas> _atlases;
|
||||
std::unordered_map<GlyphId, AtlasTextureInfo, GlyphId::Hash, GlyphId::Equal> _glyphTextureMap;
|
||||
std::vector<AtlasTextureInfo> _textureCache;
|
||||
std::array<uint32_t, SPR_IMAGE_LIST_END> _indexMap;
|
||||
|
||||
// Pixel dimensions of smallest supported slots in texture atlases
|
||||
// Must be a power of 2!
|
||||
constexpr int32_t TEXTURE_CACHE_SMALLEST_SLOT = 32;
|
||||
|
||||
struct BasicTextureInfo
|
||||
{
|
||||
GLuint index;
|
||||
vec4 normalizedBounds;
|
||||
};
|
||||
|
||||
// Location of an image (texture atlas index, slot and normalized coordinates)
|
||||
struct AtlasTextureInfo : public BasicTextureInfo
|
||||
{
|
||||
GLuint slot;
|
||||
ivec4 bounds;
|
||||
ImageIndex image;
|
||||
};
|
||||
|
||||
// Represents a texture atlas that images of a given maximum size can be allocated from
|
||||
// Atlases are all stored in the same 2D texture array, occupying the specified index
|
||||
// Slots in atlases are always squares.
|
||||
class Atlas final
|
||||
{
|
||||
private:
|
||||
GLuint _index = 0;
|
||||
int32_t _imageSize = 0;
|
||||
int32_t _atlasWidth = 0;
|
||||
int32_t _atlasHeight = 0;
|
||||
std::vector<GLuint> _freeSlots;
|
||||
|
||||
int32_t _cols = 0;
|
||||
int32_t _rows = 0;
|
||||
|
||||
public:
|
||||
Atlas(GLuint index, int32_t imageSize)
|
||||
: _index(index)
|
||||
, _imageSize(imageSize)
|
||||
{
|
||||
}
|
||||
|
||||
void Initialise(int32_t atlasWidth, int32_t atlasHeight)
|
||||
{
|
||||
_atlasWidth = atlasWidth;
|
||||
_atlasHeight = atlasHeight;
|
||||
|
||||
_cols = std::max(1, _atlasWidth / _imageSize);
|
||||
_rows = std::max(1, _atlasHeight / _imageSize);
|
||||
|
||||
_freeSlots.resize(_cols * _rows);
|
||||
for (size_t i = 0; i < _freeSlots.size(); i++)
|
||||
{
|
||||
_freeSlots[i] = static_cast<GLuint>(i);
|
||||
}
|
||||
}
|
||||
|
||||
AtlasTextureInfo Allocate(int32_t actualWidth, int32_t actualHeight)
|
||||
{
|
||||
assert(!_freeSlots.empty());
|
||||
|
||||
GLuint slot = _freeSlots.back();
|
||||
_freeSlots.pop_back();
|
||||
|
||||
auto bounds = GetSlotCoordinates(slot, actualWidth, actualHeight);
|
||||
|
||||
AtlasTextureInfo info{};
|
||||
info.index = _index;
|
||||
info.slot = slot;
|
||||
info.bounds = bounds;
|
||||
info.normalizedBounds = NormalizeCoordinates(bounds);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void Free(const AtlasTextureInfo& info)
|
||||
{
|
||||
assert(_index == info.index);
|
||||
|
||||
_freeSlots.push_back(info.slot);
|
||||
}
|
||||
|
||||
// Checks if specified image would be tightly packed in this atlas
|
||||
// by checking if it is within the right power of 2 range
|
||||
[[nodiscard]] bool IsImageSuitable(int32_t actualWidth, int32_t actualHeight) const
|
||||
{
|
||||
int32_t imageOrder = CalculateImageSizeOrder(actualWidth, actualHeight);
|
||||
int32_t atlasOrder = log2(_imageSize);
|
||||
|
||||
return imageOrder == atlasOrder;
|
||||
}
|
||||
|
||||
[[nodiscard]] int32_t GetFreeSlots() const
|
||||
{
|
||||
return static_cast<int32_t>(_freeSlots.size());
|
||||
}
|
||||
|
||||
static int32_t CalculateImageSizeOrder(int32_t actualWidth, int32_t actualHeight)
|
||||
{
|
||||
int32_t actualSize = std::max(actualWidth, actualHeight);
|
||||
|
||||
if (actualSize < TEXTURE_CACHE_SMALLEST_SLOT)
|
||||
{
|
||||
actualSize = TEXTURE_CACHE_SMALLEST_SLOT;
|
||||
}
|
||||
|
||||
return static_cast<int32_t>(ceil(log2f(static_cast<float>(actualSize))));
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] ivec4 GetSlotCoordinates(GLuint slot, int32_t actualWidth, int32_t actualHeight) const
|
||||
{
|
||||
int32_t row = slot / _cols;
|
||||
int32_t col = slot % _cols;
|
||||
|
||||
return ivec4{
|
||||
_imageSize * col,
|
||||
_imageSize * row,
|
||||
_imageSize * col + actualWidth,
|
||||
_imageSize * row + actualHeight,
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] vec4 NormalizeCoordinates(const ivec4& coords) const
|
||||
{
|
||||
return vec4{
|
||||
coords.x / static_cast<float>(_atlasWidth),
|
||||
coords.y / static_cast<float>(_atlasHeight),
|
||||
coords.z / static_cast<float>(_atlasWidth),
|
||||
coords.w / static_cast<float>(_atlasHeight),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class TextureCache final
|
||||
{
|
||||
private:
|
||||
bool _initialized = false;
|
||||
|
||||
GLuint _atlasesTexture = 0;
|
||||
GLint _atlasesTextureDimensions = 0;
|
||||
GLuint _atlasesTextureCapacity = 0;
|
||||
GLuint _atlasesTextureIndices = 0;
|
||||
GLint _atlasesTextureIndicesLimit = 0;
|
||||
std::vector<Atlas> _atlases;
|
||||
std::unordered_map<GlyphId, AtlasTextureInfo, GlyphId::Hash, GlyphId::Equal> _glyphTextureMap;
|
||||
std::vector<AtlasTextureInfo> _textureCache;
|
||||
std::array<uint32_t, SPR_IMAGE_LIST_END> _indexMap;
|
||||
|
||||
GLuint _paletteTexture = 0;
|
||||
GLuint _blendPaletteTexture = 0;
|
||||
GLuint _paletteTexture = 0;
|
||||
GLuint _blendPaletteTexture = 0;
|
||||
|
||||
#ifndef __MACOSX__
|
||||
std::shared_mutex _mutex;
|
||||
using shared_lock = std::shared_lock<std::shared_mutex>;
|
||||
using unique_lock = std::unique_lock<std::shared_mutex>;
|
||||
std::shared_mutex _mutex;
|
||||
using shared_lock = std::shared_lock<std::shared_mutex>;
|
||||
using unique_lock = std::unique_lock<std::shared_mutex>;
|
||||
#else
|
||||
std::mutex _mutex;
|
||||
using shared_lock = std::unique_lock<std::mutex>;
|
||||
using unique_lock = std::unique_lock<std::mutex>;
|
||||
std::mutex _mutex;
|
||||
using shared_lock = std::unique_lock<std::mutex>;
|
||||
using unique_lock = std::unique_lock<std::mutex>;
|
||||
#endif
|
||||
|
||||
public:
|
||||
TextureCache();
|
||||
~TextureCache();
|
||||
void InvalidateImage(ImageIndex image);
|
||||
BasicTextureInfo GetOrLoadImageTexture(const ImageId imageId);
|
||||
BasicTextureInfo GetOrLoadGlyphTexture(const ImageId imageId, const PaletteMap& paletteMap);
|
||||
BasicTextureInfo GetOrLoadBitmapTexture(ImageIndex image, const void* pixels, size_t width, size_t height);
|
||||
public:
|
||||
TextureCache();
|
||||
~TextureCache();
|
||||
void InvalidateImage(ImageIndex image);
|
||||
BasicTextureInfo GetOrLoadImageTexture(const ImageId imageId);
|
||||
BasicTextureInfo GetOrLoadGlyphTexture(const ImageId imageId, const PaletteMap& paletteMap);
|
||||
BasicTextureInfo GetOrLoadBitmapTexture(ImageIndex image, const void* pixels, size_t width, size_t height);
|
||||
|
||||
GLuint GetAtlasesTexture();
|
||||
GLuint GetPaletteTexture();
|
||||
GLuint GetBlendPaletteTexture();
|
||||
static GLint PaletteToY(FilterPaletteID palette);
|
||||
GLuint GetAtlasesTexture();
|
||||
GLuint GetPaletteTexture();
|
||||
GLuint GetBlendPaletteTexture();
|
||||
static GLint PaletteToY(FilterPaletteID palette);
|
||||
|
||||
private:
|
||||
void CreateTextures();
|
||||
void GeneratePaletteTexture();
|
||||
void EnlargeAtlasesTexture(GLuint newEntries);
|
||||
AtlasTextureInfo LoadImageTexture(const ImageId image);
|
||||
AtlasTextureInfo LoadGlyphTexture(const ImageId image, const PaletteMap& paletteMap);
|
||||
AtlasTextureInfo AllocateImage(int32_t imageWidth, int32_t imageHeight);
|
||||
AtlasTextureInfo LoadBitmapTexture(ImageIndex image, const void* pixels, size_t width, size_t height);
|
||||
static DrawPixelInfo GetImageAsDPI(const ImageId imageId);
|
||||
static DrawPixelInfo GetGlyphAsDPI(const ImageId imageId, const PaletteMap& paletteMap);
|
||||
void FreeTextures();
|
||||
private:
|
||||
void CreateTextures();
|
||||
void GeneratePaletteTexture();
|
||||
void EnlargeAtlasesTexture(GLuint newEntries);
|
||||
AtlasTextureInfo LoadImageTexture(const ImageId image);
|
||||
AtlasTextureInfo LoadGlyphTexture(const ImageId image, const PaletteMap& paletteMap);
|
||||
AtlasTextureInfo AllocateImage(int32_t imageWidth, int32_t imageHeight);
|
||||
AtlasTextureInfo LoadBitmapTexture(ImageIndex image, const void* pixels, size_t width, size_t height);
|
||||
static DrawPixelInfo GetImageAsDPI(const ImageId imageId);
|
||||
static DrawPixelInfo GetGlyphAsDPI(const ImageId imageId, const PaletteMap& paletteMap);
|
||||
void FreeTextures();
|
||||
|
||||
static DrawPixelInfo CreateDPI(int32_t width, int32_t height);
|
||||
static void DeleteDPI(DrawPixelInfo dpi);
|
||||
};
|
||||
static DrawPixelInfo CreateDPI(int32_t width, int32_t height);
|
||||
static void DeleteDPI(DrawPixelInfo dpi);
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
|
@ -15,194 +15,196 @@
|
|||
# include <map>
|
||||
# include <vector>
|
||||
|
||||
/*
|
||||
* Structure to store locations of vertical bounding box edge.
|
||||
*/
|
||||
struct XData
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
int32_t xposition;
|
||||
bool begin;
|
||||
int32_t top, bottom;
|
||||
};
|
||||
using SweepLine = std::vector<XData>;
|
||||
|
||||
/*
|
||||
* Creates a list of vertical bounding box edges, stored as xdata and sorted
|
||||
* from left to right. If multiple edges are at the same x coordinate, Then
|
||||
* edges for boxes to the left will appear before edges for boxes to the right.
|
||||
*/
|
||||
static inline SweepLine CreateXList(const RectCommandBatch& transparent)
|
||||
{
|
||||
SweepLine x_sweep;
|
||||
x_sweep.reserve(transparent.size() * 2);
|
||||
|
||||
for (const DrawRectCommand& command : transparent)
|
||||
/*
|
||||
* Structure to store locations of vertical bounding box edge.
|
||||
*/
|
||||
struct XData
|
||||
{
|
||||
int32_t left = std::min(std::max(command.bounds.x, command.clip.x), command.clip.z);
|
||||
int32_t top = std::min(std::max(command.bounds.y, command.clip.y), command.clip.w);
|
||||
int32_t right = std::min(std::max(command.bounds.z, command.clip.x), command.clip.z);
|
||||
int32_t bottom = std::min(std::max(command.bounds.w, command.clip.y), command.clip.w);
|
||||
int32_t xposition;
|
||||
bool begin;
|
||||
int32_t top, bottom;
|
||||
};
|
||||
using SweepLine = std::vector<XData>;
|
||||
|
||||
assert(left <= right);
|
||||
assert(top <= bottom);
|
||||
if (left == right)
|
||||
continue;
|
||||
if (top == bottom)
|
||||
continue;
|
||||
|
||||
x_sweep.push_back({ left, true, top, bottom });
|
||||
x_sweep.push_back({ right, false, top, bottom });
|
||||
}
|
||||
|
||||
std::sort(x_sweep.begin(), x_sweep.end(), [](const XData& a, const XData& b) -> bool {
|
||||
if (a.xposition != b.xposition)
|
||||
return a.xposition < b.xposition;
|
||||
|
||||
return !a.begin && b.begin;
|
||||
});
|
||||
|
||||
return x_sweep;
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure that stores intervals. YData.count stores how many intervals have
|
||||
* an endpoint at this position, and YData.depth stores how many intervals
|
||||
* intersect on the left limit of this point. In other words, IntervalTree
|
||||
* stores half-closed intervals, with the left endpoint open, and the right
|
||||
* endpoint closed. The IntervalTree uses std::map because it stores the values
|
||||
* sorted, and we can traverse it in order using its bidirectional iterators.
|
||||
*/
|
||||
struct YData
|
||||
{
|
||||
int32_t count, depth;
|
||||
};
|
||||
using IntervalTree = std::map<int32_t, YData>;
|
||||
|
||||
/*
|
||||
* Inserts the interval's top endpoint into the interval tree. If the endpoint
|
||||
* already exists in the interval tree, it stacks the endpoints.
|
||||
*/
|
||||
static inline IntervalTree::iterator InsertTopEndpoint(IntervalTree& y_intersect, int32_t top)
|
||||
{
|
||||
auto top_in = y_intersect.insert({ top, { 1, 0 } });
|
||||
IntervalTree::iterator top_it = top_in.first;
|
||||
if (top_in.second)
|
||||
/*
|
||||
* Creates a list of vertical bounding box edges, stored as xdata and sorted
|
||||
* from left to right. If multiple edges are at the same x coordinate, Then
|
||||
* edges for boxes to the left will appear before edges for boxes to the right.
|
||||
*/
|
||||
static inline SweepLine CreateXList(const RectCommandBatch& transparent)
|
||||
{
|
||||
IntervalTree::iterator top_next = std::next(top_it);
|
||||
if (top_next != y_intersect.end())
|
||||
SweepLine x_sweep;
|
||||
x_sweep.reserve(transparent.size() * 2);
|
||||
|
||||
for (const DrawRectCommand& command : transparent)
|
||||
{
|
||||
top_it->second.depth = top_next->second.depth;
|
||||
int32_t left = std::min(std::max(command.bounds.x, command.clip.x), command.clip.z);
|
||||
int32_t top = std::min(std::max(command.bounds.y, command.clip.y), command.clip.w);
|
||||
int32_t right = std::min(std::max(command.bounds.z, command.clip.x), command.clip.z);
|
||||
int32_t bottom = std::min(std::max(command.bounds.w, command.clip.y), command.clip.w);
|
||||
|
||||
assert(left <= right);
|
||||
assert(top <= bottom);
|
||||
if (left == right)
|
||||
continue;
|
||||
if (top == bottom)
|
||||
continue;
|
||||
|
||||
x_sweep.push_back({ left, true, top, bottom });
|
||||
x_sweep.push_back({ right, false, top, bottom });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++top_it->second.count;
|
||||
}
|
||||
return top_it;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inserts the interval's bottom endpoint into the interval tree. If the
|
||||
* endpoint already exists in the interval tree, it stacks the endpoint.
|
||||
* This function can produce a new maximum depth.
|
||||
*/
|
||||
static inline IntervalTree::iterator InsertBottomEndpoint(IntervalTree& y_intersect, int32_t bottom)
|
||||
{
|
||||
auto bottom_in = y_intersect.insert({ bottom, { 1, 1 } });
|
||||
IntervalTree::iterator bottom_it = bottom_in.first;
|
||||
if (bottom_in.second)
|
||||
std::sort(x_sweep.begin(), x_sweep.end(), [](const XData& a, const XData& b) -> bool {
|
||||
if (a.xposition != b.xposition)
|
||||
return a.xposition < b.xposition;
|
||||
|
||||
return !a.begin && b.begin;
|
||||
});
|
||||
|
||||
return x_sweep;
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure that stores intervals. YData.count stores how many intervals have
|
||||
* an endpoint at this position, and YData.depth stores how many intervals
|
||||
* intersect on the left limit of this point. In other words, IntervalTree
|
||||
* stores half-closed intervals, with the left endpoint open, and the right
|
||||
* endpoint closed. The IntervalTree uses std::map because it stores the values
|
||||
* sorted, and we can traverse it in order using its bidirectional iterators.
|
||||
*/
|
||||
struct YData
|
||||
{
|
||||
IntervalTree::iterator bottom_next = std::next(bottom_it);
|
||||
if (bottom_next != y_intersect.end())
|
||||
int32_t count, depth;
|
||||
};
|
||||
using IntervalTree = std::map<int32_t, YData>;
|
||||
|
||||
/*
|
||||
* Inserts the interval's top endpoint into the interval tree. If the endpoint
|
||||
* already exists in the interval tree, it stacks the endpoints.
|
||||
*/
|
||||
static inline IntervalTree::iterator InsertTopEndpoint(IntervalTree& y_intersect, int32_t top)
|
||||
{
|
||||
auto top_in = y_intersect.insert({ top, { 1, 0 } });
|
||||
IntervalTree::iterator top_it = top_in.first;
|
||||
if (top_in.second)
|
||||
{
|
||||
bottom_it->second.depth = bottom_next->second.depth + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++bottom_it->second.count;
|
||||
++bottom_it->second.depth;
|
||||
}
|
||||
return bottom_it;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes the interval's top endpoint, handling stacked endpoints.
|
||||
*/
|
||||
static inline void RemoveTopEndpoint(IntervalTree& y_intersect, IntervalTree::iterator top_it)
|
||||
{
|
||||
if (top_it->second.count == 1)
|
||||
{
|
||||
y_intersect.erase(top_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
--top_it->second.count;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes the interval's bottom endpoint, handling stacked endpoints.
|
||||
*/
|
||||
static inline void RemoveBottomEndpoint(IntervalTree& y_intersect, IntervalTree::iterator bottom_it)
|
||||
{
|
||||
if (bottom_it->second.count == 1)
|
||||
{
|
||||
y_intersect.erase(bottom_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
--bottom_it->second.count;
|
||||
--bottom_it->second.depth;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines an approximation of the number of depth peeling iterations needed
|
||||
* to render the command batch. It will never underestimate the number of
|
||||
* iterations, but it can overestimate, usually by no more than +2.
|
||||
*/
|
||||
int32_t MaxTransparencyDepth(const RectCommandBatch& transparent)
|
||||
{
|
||||
int32_t max_depth = 1;
|
||||
SweepLine x_sweep = CreateXList(transparent);
|
||||
IntervalTree y_intersect{};
|
||||
|
||||
for (const XData& x : x_sweep)
|
||||
{
|
||||
if (x.begin)
|
||||
{
|
||||
IntervalTree::iterator top_it = InsertTopEndpoint(y_intersect, x.top);
|
||||
IntervalTree::iterator bottom_it = InsertBottomEndpoint(y_intersect, x.bottom);
|
||||
max_depth = std::max(max_depth, bottom_it->second.depth);
|
||||
|
||||
/*
|
||||
* Increment the depth for endpoings that intersect this interval
|
||||
*/
|
||||
for (IntervalTree::iterator it = std::next(top_it); it != bottom_it && it != std::end(y_intersect); ++it)
|
||||
IntervalTree::iterator top_next = std::next(top_it);
|
||||
if (top_next != y_intersect.end())
|
||||
{
|
||||
max_depth = std::max(max_depth, ++it->second.depth);
|
||||
top_it->second.depth = top_next->second.depth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IntervalTree::iterator top_it = y_intersect.find(x.top);
|
||||
IntervalTree::iterator bottom_it = y_intersect.find(x.bottom);
|
||||
++top_it->second.count;
|
||||
}
|
||||
return top_it;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement the depth for endpoings that intersected this interval
|
||||
*/
|
||||
for (IntervalTree::iterator it = std::next(top_it); it != bottom_it && it != std::end(y_intersect); ++it)
|
||||
/*
|
||||
* Inserts the interval's bottom endpoint into the interval tree. If the
|
||||
* endpoint already exists in the interval tree, it stacks the endpoint.
|
||||
* This function can produce a new maximum depth.
|
||||
*/
|
||||
static inline IntervalTree::iterator InsertBottomEndpoint(IntervalTree& y_intersect, int32_t bottom)
|
||||
{
|
||||
auto bottom_in = y_intersect.insert({ bottom, { 1, 1 } });
|
||||
IntervalTree::iterator bottom_it = bottom_in.first;
|
||||
if (bottom_in.second)
|
||||
{
|
||||
IntervalTree::iterator bottom_next = std::next(bottom_it);
|
||||
if (bottom_next != y_intersect.end())
|
||||
{
|
||||
--it->second.depth;
|
||||
bottom_it->second.depth = bottom_next->second.depth + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++bottom_it->second.count;
|
||||
++bottom_it->second.depth;
|
||||
}
|
||||
return bottom_it;
|
||||
}
|
||||
|
||||
RemoveTopEndpoint(y_intersect, top_it);
|
||||
RemoveBottomEndpoint(y_intersect, bottom_it);
|
||||
/*
|
||||
* Removes the interval's top endpoint, handling stacked endpoints.
|
||||
*/
|
||||
static inline void RemoveTopEndpoint(IntervalTree& y_intersect, IntervalTree::iterator top_it)
|
||||
{
|
||||
if (top_it->second.count == 1)
|
||||
{
|
||||
y_intersect.erase(top_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
--top_it->second.count;
|
||||
}
|
||||
}
|
||||
|
||||
return max_depth;
|
||||
}
|
||||
/*
|
||||
* Removes the interval's bottom endpoint, handling stacked endpoints.
|
||||
*/
|
||||
static inline void RemoveBottomEndpoint(IntervalTree& y_intersect, IntervalTree::iterator bottom_it)
|
||||
{
|
||||
if (bottom_it->second.count == 1)
|
||||
{
|
||||
y_intersect.erase(bottom_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
--bottom_it->second.count;
|
||||
--bottom_it->second.depth;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines an approximation of the number of depth peeling iterations needed
|
||||
* to render the command batch. It will never underestimate the number of
|
||||
* iterations, but it can overestimate, usually by no more than +2.
|
||||
*/
|
||||
int32_t MaxTransparencyDepth(const RectCommandBatch& transparent)
|
||||
{
|
||||
int32_t max_depth = 1;
|
||||
SweepLine x_sweep = CreateXList(transparent);
|
||||
IntervalTree y_intersect{};
|
||||
|
||||
for (const XData& x : x_sweep)
|
||||
{
|
||||
if (x.begin)
|
||||
{
|
||||
IntervalTree::iterator top_it = InsertTopEndpoint(y_intersect, x.top);
|
||||
IntervalTree::iterator bottom_it = InsertBottomEndpoint(y_intersect, x.bottom);
|
||||
max_depth = std::max(max_depth, bottom_it->second.depth);
|
||||
|
||||
/*
|
||||
* Increment the depth for endpoings that intersect this interval
|
||||
*/
|
||||
for (IntervalTree::iterator it = std::next(top_it); it != bottom_it && it != std::end(y_intersect); ++it)
|
||||
{
|
||||
max_depth = std::max(max_depth, ++it->second.depth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IntervalTree::iterator top_it = y_intersect.find(x.top);
|
||||
IntervalTree::iterator bottom_it = y_intersect.find(x.bottom);
|
||||
|
||||
/*
|
||||
* Decrement the depth for endpoings that intersected this interval
|
||||
*/
|
||||
for (IntervalTree::iterator it = std::next(top_it); it != bottom_it && it != std::end(y_intersect); ++it)
|
||||
{
|
||||
--it->second.depth;
|
||||
}
|
||||
|
||||
RemoveTopEndpoint(y_intersect, top_it);
|
||||
RemoveBottomEndpoint(y_intersect, bottom_it);
|
||||
}
|
||||
}
|
||||
|
||||
return max_depth;
|
||||
}
|
||||
} // namespace OpenRCT2::Ui
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
|
|
@ -13,9 +13,12 @@
|
|||
|
||||
#include <openrct2/common.h>
|
||||
|
||||
/*
|
||||
* Determines an approximation of the number of depth peeling iterations needed
|
||||
* to render the command batch. It will never underestimate the number of
|
||||
* iterations, but it can overestimate, usually by no more than +2.
|
||||
*/
|
||||
int32_t MaxTransparencyDepth(const RectCommandBatch& transparent);
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
/*
|
||||
* Determines an approximation of the number of depth peeling iterations needed
|
||||
* to render the command batch. It will never underestimate the number of
|
||||
* iterations, but it can overestimate, usually by no more than +2.
|
||||
*/
|
||||
int32_t MaxTransparencyDepth(const RectCommandBatch& transparent);
|
||||
} // namespace OpenRCT2::Ui
|
||||
|
|
Loading…
Reference in New Issue