mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-06 06:32:56 +01:00
Move MaxTransparencyDepth
This commit is contained in:
committed by
Michał Janiszewski
parent
7db8d0f00a
commit
50600f6195
@@ -266,6 +266,7 @@
|
||||
D45E09171F99CF2F00854B2B /* ApplyTransparencyShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D45E09161F99CF2F00854B2B /* ApplyTransparencyShader.cpp */; };
|
||||
D47304D51C4FF8250015C0EA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D47304D41C4FF8250015C0EA /* libz.tbd */; };
|
||||
D48AFDB71EF78DBF0081C644 /* BenchGfxCommmands.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D48AFDB61EF78DBF0081C644 /* BenchGfxCommmands.cpp */; };
|
||||
D4974F1C1FA04A1900F7FD7F /* TransparencyDepth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D4974F1A1FA04A1900F7FD7F /* TransparencyDepth.cpp */; };
|
||||
D4A8B4B41DB41873007A2F29 /* libpng16.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A8B4B31DB41873007A2F29 /* libpng16.dylib */; };
|
||||
D4A8B4B51DB4188D007A2F29 /* libpng16.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D4A8B4B31DB41873007A2F29 /* libpng16.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
D4EC48E61C2637710024B507 /* g2.dat in Resources */ = {isa = PBXBuildFile; fileRef = D4EC48E31C2637710024B507 /* g2.dat */; };
|
||||
@@ -1040,6 +1041,8 @@
|
||||
D47304D41C4FF8250015C0EA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
D4895D321C23EFDD000CD788 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = distribution/macos/Info.plist; sourceTree = SOURCE_ROOT; };
|
||||
D48AFDB61EF78DBF0081C644 /* BenchGfxCommmands.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BenchGfxCommmands.cpp; sourceTree = "<group>"; };
|
||||
D4974F1A1FA04A1900F7FD7F /* TransparencyDepth.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TransparencyDepth.cpp; sourceTree = "<group>"; };
|
||||
D4974F1B1FA04A1900F7FD7F /* TransparencyDepth.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TransparencyDepth.h; sourceTree = "<group>"; };
|
||||
D497D0781C20FD52002BF46A /* OpenRCT2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OpenRCT2.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D4A8B4B31DB41873007A2F29 /* libpng16.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libpng16.dylib; sourceTree = "<group>"; };
|
||||
D4EC48E31C2637710024B507 /* g2.dat */ = {isa = PBXFileReference; lastKnownFileType = file; name = g2.dat; path = data/g2.dat; sourceTree = SOURCE_ROOT; };
|
||||
@@ -2688,6 +2691,8 @@
|
||||
F76C85A31EC4E82600FA49E2 /* SwapFramebuffer.h */,
|
||||
F76C85A41EC4E82600FA49E2 /* TextureCache.cpp */,
|
||||
F76C85A51EC4E82600FA49E2 /* TextureCache.h */,
|
||||
D4974F1A1FA04A1900F7FD7F /* TransparencyDepth.cpp */,
|
||||
D4974F1B1FA04A1900F7FD7F /* TransparencyDepth.h */,
|
||||
);
|
||||
path = opengl;
|
||||
sourceTree = "<group>";
|
||||
@@ -3150,6 +3155,7 @@
|
||||
4CFE4E821F90A3F1005243C2 /* Staff.cpp in Sources */,
|
||||
F76C88791EC5324E00FA49E2 /* AudioContext.cpp in Sources */,
|
||||
4C93F1571F8B744400A9330D /* WildMouse.cpp in Sources */,
|
||||
D4974F1C1FA04A1900F7FD7F /* TransparencyDepth.cpp in Sources */,
|
||||
C666EE7A1F37ACB10061AA04 /* Themes.cpp in Sources */,
|
||||
4C93F1781F8B745700A9330D /* SpaceRings.cpp in Sources */,
|
||||
4CFE4E8A1F950164005243C2 /* TrackDataOld.cpp in Sources */,
|
||||
|
||||
@@ -70,14 +70,31 @@ public:
|
||||
{
|
||||
return _instances.at(idx);
|
||||
}
|
||||
|
||||
typename std::vector<T>::iterator begin()
|
||||
{
|
||||
return _instances.begin();
|
||||
}
|
||||
typename std::vector<T>::const_iterator begin() const
|
||||
{
|
||||
return _instances.cbegin();
|
||||
}
|
||||
typename std::vector<T>::const_iterator cbegin() const
|
||||
{
|
||||
return _instances.cbegin();
|
||||
}
|
||||
typename std::vector<T>::iterator end()
|
||||
{
|
||||
return _instances.begin() + _numInstances;
|
||||
}
|
||||
typename std::vector<T>::const_iterator end() const
|
||||
{
|
||||
return _instances.cbegin() + _numInstances;
|
||||
}
|
||||
typename std::vector<T>::const_iterator cend() const
|
||||
{
|
||||
return _instances.cbegin() + _numInstances;
|
||||
}
|
||||
};
|
||||
|
||||
struct DrawLineCommand
|
||||
|
||||
@@ -16,10 +16,7 @@
|
||||
|
||||
#ifndef DISABLE_OPENGL
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <SDL.h>
|
||||
|
||||
#include <openrct2/config/Config.h>
|
||||
@@ -43,11 +40,12 @@
|
||||
#include "OpenGLAPI.h"
|
||||
#include "OpenGLFramebuffer.h"
|
||||
#include "CopyFramebufferShader.h"
|
||||
#include "DrawCommands.h"
|
||||
#include "DrawLineShader.h"
|
||||
#include "DrawRectShader.h"
|
||||
#include "SwapFramebuffer.h"
|
||||
#include "TextureCache.h"
|
||||
#include "DrawCommands.h"
|
||||
#include "TransparencyDepth.h"
|
||||
|
||||
using namespace OpenRCT2;
|
||||
using namespace OpenRCT2::Drawing;
|
||||
@@ -122,7 +120,6 @@ public:
|
||||
void HandleTransparency();
|
||||
|
||||
void SetDPI(rct_drawpixelinfo * dpi);
|
||||
sint32 MaxTransparencyDepth();
|
||||
};
|
||||
|
||||
class OpenGLDrawingEngine : public IDrawingEngine
|
||||
@@ -882,7 +879,7 @@ void OpenGLDrawingContext::HandleTransparency()
|
||||
_drawRectShader->Use();
|
||||
_drawRectShader->SetInstances(_commandBuffers.transparent);
|
||||
|
||||
sint32 max_depth = MaxTransparencyDepth();
|
||||
sint32 max_depth = MaxTransparencyDepth(_commandBuffers.transparent);
|
||||
for (sint32 i=0; i < max_depth; ++i)
|
||||
{
|
||||
_swapFramebuffer->BindTransparent();
|
||||
@@ -928,141 +925,4 @@ void OpenGLDrawingContext::SetDPI(rct_drawpixelinfo * dpi)
|
||||
_dpi = dpi;
|
||||
}
|
||||
|
||||
sint32 OpenGLDrawingContext::MaxTransparencyDepth()
|
||||
{
|
||||
sint32 max_depth = 1;
|
||||
|
||||
struct xdata
|
||||
{
|
||||
sint32 xposition;
|
||||
bool begin;
|
||||
sint32 top, bottom;
|
||||
};
|
||||
std::vector<xdata> x_sweep;
|
||||
x_sweep.reserve(_commandBuffers.transparent.size() * 2);
|
||||
for (DrawRectCommand &command : _commandBuffers.transparent)
|
||||
{
|
||||
sint32 left = std::min(std::max(command.bounds.x, command.clip.x), command.clip.z);
|
||||
sint32 top = std::min(std::max(command.bounds.y, command.clip.y), command.clip.w);
|
||||
sint32 right = std::min(std::max(command.bounds.z, command.clip.x), command.clip.z);
|
||||
sint32 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});
|
||||
}
|
||||
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;
|
||||
else return !a.begin && b.begin;
|
||||
});
|
||||
|
||||
struct ydata
|
||||
{
|
||||
sint32 count, depth;
|
||||
};
|
||||
std::map<sint32, ydata> y_intersect;
|
||||
for (const xdata &x : x_sweep)
|
||||
{
|
||||
assert(y_intersect.size() == 0 || y_intersect.begin()->second.depth == 0);
|
||||
if (x.begin)
|
||||
{
|
||||
auto top_in = y_intersect.insert({x.top, {1, 0}});
|
||||
auto top_it = top_in.first;
|
||||
if (top_in.second)
|
||||
{
|
||||
auto top_next = std::next(top_it);
|
||||
if (top_next != y_intersect.end())
|
||||
{
|
||||
top_it->second.depth = top_next->second.depth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(top_it->second.count > 0);
|
||||
++top_it->second.count;
|
||||
}
|
||||
|
||||
auto bottom_in = y_intersect.insert({x.bottom, {1, 1}});
|
||||
auto bottom_it = bottom_in.first;
|
||||
if (bottom_in.second)
|
||||
{
|
||||
auto bottom_next = std::next(bottom_it);
|
||||
if (bottom_next != y_intersect.end())
|
||||
{
|
||||
bottom_it->second.depth = bottom_next->second.depth + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(bottom_it->second.count > 0);
|
||||
++bottom_it->second.count;
|
||||
max_depth = std::max(max_depth, ++bottom_it->second.depth);
|
||||
}
|
||||
|
||||
for (auto it = std::next(top_it); it != bottom_it; ++it)
|
||||
{
|
||||
max_depth = std::max(max_depth, ++it->second.depth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto top_it = y_intersect.find(x.top);
|
||||
assert(top_it != y_intersect.end());
|
||||
assert(top_it->second.count > 0);
|
||||
auto bottom_it = y_intersect.find(x.bottom);
|
||||
assert(bottom_it != y_intersect.end());
|
||||
assert(bottom_it->second.count > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (top_it->second.count == 1)
|
||||
{
|
||||
auto top_next = std::next(top_it);
|
||||
assert(top_next != y_intersect.end() &&
|
||||
top_it->second.depth == top_next->second.depth - 1);
|
||||
}
|
||||
|
||||
if (bottom_it->second.count == 1)
|
||||
{
|
||||
auto bottom_next = std::next(bottom_it);
|
||||
assert(bottom_next == y_intersect.end() ?
|
||||
bottom_it->second.depth == 1 :
|
||||
bottom_it->second.depth == bottom_next->second.depth + 1);
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
|
||||
for (auto it = std::next(top_it); it != bottom_it; ++it)
|
||||
{
|
||||
assert(it->second.depth > 0);
|
||||
--it->second.depth;
|
||||
}
|
||||
|
||||
if (top_it->second.count == 1)
|
||||
{
|
||||
y_intersect.erase(top_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
--top_it->second.count;
|
||||
}
|
||||
|
||||
if (bottom_it->second.count == 1)
|
||||
{
|
||||
y_intersect.erase(bottom_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(bottom_it->second.depth > 0);
|
||||
--bottom_it->second.count;
|
||||
--bottom_it->second.depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return max_depth;
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
||||
211
src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.cpp
Normal file
211
src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#ifndef DISABLE_OPENGL
|
||||
|
||||
#include "TransparencyDepth.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
* Structure to store locations of vertical bounding box edge.
|
||||
*/
|
||||
struct XData
|
||||
{
|
||||
sint32 xposition;
|
||||
bool begin;
|
||||
sint32 top, bottom;
|
||||
};
|
||||
typedef std::vector<XData> SweepLine;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
sint32 left = std::min(std::max(command.bounds.x, command.clip.x), command.clip.z);
|
||||
sint32 top = std::min(std::max(command.bounds.y, command.clip.y), command.clip.w);
|
||||
sint32 right = std::min(std::max(command.bounds.z, command.clip.x), command.clip.z);
|
||||
sint32 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});
|
||||
}
|
||||
|
||||
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;
|
||||
else 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
|
||||
{
|
||||
sint32 count, depth;
|
||||
};
|
||||
typedef std::map<sint32, YData> IntervalTree;
|
||||
|
||||
/*
|
||||
* 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, sint32 top)
|
||||
{
|
||||
auto top_in = y_intersect.insert({top, {1, 0}});
|
||||
IntervalTree::iterator top_it = top_in.first;
|
||||
if (top_in.second)
|
||||
{
|
||||
IntervalTree::iterator top_next = std::next(top_it);
|
||||
if (top_next != y_intersect.end())
|
||||
{
|
||||
top_it->second.depth = top_next->second.depth;
|
||||
}
|
||||
}
|
||||
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, sint32 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())
|
||||
{
|
||||
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 aproximation 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.
|
||||
*/
|
||||
sint32 MaxTransparencyDepth(const RectCommandBatch &transparent)
|
||||
{
|
||||
sint32 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
--it->second.depth;
|
||||
}
|
||||
|
||||
RemoveTopEndpoint(y_intersect, top_it);
|
||||
RemoveBottomEndpoint(y_intersect, bottom_it);
|
||||
}
|
||||
}
|
||||
|
||||
return max_depth;
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
27
src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.h
Normal file
27
src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <openrct2/common.h>
|
||||
#include "DrawCommands.h"
|
||||
|
||||
/*
|
||||
* Determines an aproximation 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.
|
||||
*/
|
||||
sint32 MaxTransparencyDepth(const RectCommandBatch &transparent);
|
||||
Reference in New Issue
Block a user