2 features: multi-sample anti-aliasing & Lua patches for images
This commit is contained in:
parent
4458d2e85e
commit
8a8a050159
Binary file not shown.
Before Width: | Height: | Size: 754 B |
6
assets/opensb/interface/graphicsmenu/body.png.patch.lua
Normal file
6
assets/opensb/interface/graphicsmenu/body.png.patch.lua
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
function patch(image)
|
||||||
|
-- Camera Pan Speed
|
||||||
|
image:copyInto({119, 68}, image:process("?crop=19;68;117;87"))
|
||||||
|
-- Anti-Aliasing
|
||||||
|
image:copyInto({119, 26}, image:process("?crop=19;26;117;35"))
|
||||||
|
end
|
@ -1,70 +0,0 @@
|
|||||||
{
|
|
||||||
"paneLayout": {
|
|
||||||
"panefeature": { "positionLocked": false },
|
|
||||||
"cameraSpeedLabel" : {
|
|
||||||
"type" : "label",
|
|
||||||
"position" : [170, 112],
|
|
||||||
"hAnchor" : "mid",
|
|
||||||
"value" : "CAMERA PAN SPEED"
|
|
||||||
},
|
|
||||||
"cameraSpeedValueLabel" : {
|
|
||||||
"type" : "label",
|
|
||||||
"position" : [202, 99],
|
|
||||||
"hAnchor" : "mid",
|
|
||||||
"value" : "Replace Me"
|
|
||||||
},
|
|
||||||
"cameraSpeedSlider" : {
|
|
||||||
"type" : "slider",
|
|
||||||
"position" : [126, 98],
|
|
||||||
"gridImage" : "/interface/optionsmenu/smallselection.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"zoomList": [
|
|
||||||
1,
|
|
||||||
1.125,
|
|
||||||
1.25,
|
|
||||||
1.375,
|
|
||||||
1.5,
|
|
||||||
1.675,
|
|
||||||
1.75,
|
|
||||||
1.875,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4,
|
|
||||||
5,
|
|
||||||
6,
|
|
||||||
7,
|
|
||||||
8,
|
|
||||||
9,
|
|
||||||
10,
|
|
||||||
11,
|
|
||||||
12,
|
|
||||||
13,
|
|
||||||
14,
|
|
||||||
15,
|
|
||||||
16,
|
|
||||||
17,
|
|
||||||
18,
|
|
||||||
19,
|
|
||||||
20,
|
|
||||||
21,
|
|
||||||
22,
|
|
||||||
23,
|
|
||||||
24,
|
|
||||||
25,
|
|
||||||
26,
|
|
||||||
27,
|
|
||||||
28,
|
|
||||||
29,
|
|
||||||
30,
|
|
||||||
31,
|
|
||||||
32
|
|
||||||
],
|
|
||||||
"cameraSpeedList" : [
|
|
||||||
0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
|
|
||||||
1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
|
|
||||||
2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0,
|
|
||||||
3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0,
|
|
||||||
4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0
|
|
||||||
]
|
|
||||||
}
|
|
@ -0,0 +1,35 @@
|
|||||||
|
-- gadgets
|
||||||
|
local function jcopy(base) return sb.jsonMerge(base, {}) end
|
||||||
|
|
||||||
|
local function clone(base, a, b)
|
||||||
|
local copy = jcopy(base[a])
|
||||||
|
base[b] = copy
|
||||||
|
return copy
|
||||||
|
end
|
||||||
|
|
||||||
|
local function shift(thing, x, y)
|
||||||
|
thing.position[1] = thing.position[1] + (tonumber(x) or 0)
|
||||||
|
thing.position[2] = thing.position[2] + (tonumber(y) or 0)
|
||||||
|
return thing
|
||||||
|
end
|
||||||
|
|
||||||
|
-- patch function, called by the game
|
||||||
|
function patch(config)
|
||||||
|
local layout = config.paneLayout
|
||||||
|
layout.panefeature.positionLocked = false
|
||||||
|
|
||||||
|
-- Create the camera pan speed widgets
|
||||||
|
shift(clone(layout, "zoomLabel", "cameraSpeedLabel"), 100).value = "CAMERA PAN SPEED"
|
||||||
|
shift(clone(layout, "zoomSlider", "cameraSpeedSlider"), 100)
|
||||||
|
shift(clone(layout, "zoomValueLabel", "cameraSpeedValueLabel"), 100)
|
||||||
|
-- Populate camera speed list
|
||||||
|
config.cameraSpeedList = jarray()
|
||||||
|
for i = 1, 50 do config.cameraSpeedList[i] = i / 10 end
|
||||||
|
for i = 1, 32 do config.zoomList[i] = i end
|
||||||
|
|
||||||
|
-- Create anti-aliasing toggle
|
||||||
|
shift(clone(layout, "multiTextureLabel", "antiAliasingLabel"), 100).value = "SUPER-SAMPLED AA"
|
||||||
|
shift(clone(layout, "multiTextureCheckbox", "antiAliasingCheckbox"), 100)
|
||||||
|
|
||||||
|
return config
|
||||||
|
end
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"blitFrameBuffer" : "world",
|
"blitFrameBuffer" : "main",
|
||||||
|
|
||||||
"effectParameters" : {},
|
"effectParameters" : {},
|
||||||
"effectTextures" : {},
|
"effectTextures" : {},
|
||||||
|
@ -1,27 +1,29 @@
|
|||||||
#version 110
|
#version 130
|
||||||
|
|
||||||
uniform sampler2D texture0;
|
uniform sampler2D texture0;
|
||||||
uniform sampler2D texture1;
|
uniform sampler2D texture1;
|
||||||
uniform sampler2D texture2;
|
uniform sampler2D texture2;
|
||||||
uniform sampler2D texture3;
|
uniform sampler2D texture3;
|
||||||
|
|
||||||
varying vec2 fragmentTextureCoordinate;
|
in vec2 fragmentTextureCoordinate;
|
||||||
varying float fragmentTextureIndex;
|
flat in int fragmentTextureIndex;
|
||||||
varying vec4 fragmentColor;
|
in vec4 fragmentColor;
|
||||||
|
|
||||||
|
out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 texColor;
|
vec4 texColor;
|
||||||
if (fragmentTextureIndex > 2.9) {
|
if (fragmentTextureIndex == 3)
|
||||||
texColor = texture2D(texture3, fragmentTextureCoordinate);
|
texColor = texture2D(texture3, fragmentTextureCoordinate);
|
||||||
} else if (fragmentTextureIndex > 1.9) {
|
else if (fragmentTextureIndex == 2)
|
||||||
texColor = texture2D(texture2, fragmentTextureCoordinate);
|
texColor = texture2D(texture2, fragmentTextureCoordinate);
|
||||||
} else if (fragmentTextureIndex > 0.9) {
|
else if (fragmentTextureIndex == 1)
|
||||||
texColor = texture2D(texture1, fragmentTextureCoordinate);
|
texColor = texture2D(texture1, fragmentTextureCoordinate);
|
||||||
} else {
|
else
|
||||||
texColor = texture2D(texture0, fragmentTextureCoordinate);
|
texColor = texture2D(texture0, fragmentTextureCoordinate);
|
||||||
}
|
|
||||||
if (texColor.a <= 0.0)
|
if (texColor.a <= 0.0)
|
||||||
discard;
|
discard;
|
||||||
|
|
||||||
gl_FragColor = texColor * fragmentColor;
|
outColor = texColor * fragmentColor;
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
#version 110
|
#version 130
|
||||||
|
|
||||||
uniform vec2 textureSize0;
|
uniform vec2 textureSize0;
|
||||||
uniform vec2 textureSize1;
|
uniform vec2 textureSize1;
|
||||||
@ -7,28 +7,32 @@ uniform vec2 textureSize3;
|
|||||||
uniform vec2 screenSize;
|
uniform vec2 screenSize;
|
||||||
uniform mat3 vertexTransform;
|
uniform mat3 vertexTransform;
|
||||||
|
|
||||||
attribute vec2 vertexPosition;
|
in vec2 vertexPosition;
|
||||||
attribute vec2 vertexTextureCoordinate;
|
in vec4 vertexColor;
|
||||||
attribute float vertexTextureIndex;
|
in vec2 vertexTextureCoordinate;
|
||||||
attribute vec4 vertexColor;
|
in int vertexData;
|
||||||
|
|
||||||
varying vec2 fragmentTextureCoordinate;
|
out vec2 fragmentTextureCoordinate;
|
||||||
varying float fragmentTextureIndex;
|
flat out int fragmentTextureIndex;
|
||||||
varying vec4 fragmentColor;
|
out vec4 fragmentColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 screenPosition = (vertexTransform * vec3(vertexPosition, 1.0)).xy;
|
vec2 screenPosition = (vertexTransform * vec3(vertexPosition, 1.0)).xy;
|
||||||
|
gl_Position = vec4(screenPosition / screenSize * 2.0 - 1.0, 0.0, 1.0);
|
||||||
if (vertexTextureIndex > 2.9) {
|
if (((vertexData >> 3) & 0x1) == 1)
|
||||||
|
screenPosition.x = round(screenPosition.x);
|
||||||
|
if (((vertexData >> 4) & 0x1) == 1)
|
||||||
|
screenPosition.y = round(screenPosition.y);
|
||||||
|
int vertexTextureIndex = vertexData & 0x3;
|
||||||
|
if (vertexTextureIndex == 3)
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize3;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize3;
|
||||||
} else if (vertexTextureIndex > 1.9) {
|
else if (vertexTextureIndex == 2)
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize2;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize2;
|
||||||
} else if (vertexTextureIndex > 0.9) {
|
else if (vertexTextureIndex == 1)
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize1;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize1;
|
||||||
} else {
|
else
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize0;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize0;
|
||||||
}
|
|
||||||
fragmentTextureIndex = vertexTextureIndex;
|
fragmentTextureIndex = vertexTextureIndex;
|
||||||
fragmentColor = vertexColor;
|
fragmentColor = vertexColor;
|
||||||
gl_Position = vec4(screenPosition / screenSize * 2.0 - 1.0, 0.0, 1.0);
|
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"frameBuffer" : "world",
|
"frameBuffer" : "main",
|
||||||
|
|
||||||
"effectParameters" : {
|
"effectParameters" : {
|
||||||
"lightMapEnabled" : {
|
"lightMapEnabled" : {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#version 110
|
#version 130
|
||||||
|
|
||||||
uniform sampler2D texture0;
|
uniform sampler2D texture0;
|
||||||
uniform sampler2D texture1;
|
uniform sampler2D texture1;
|
||||||
@ -9,11 +9,13 @@ uniform vec2 lightMapSize;
|
|||||||
uniform sampler2D lightMap;
|
uniform sampler2D lightMap;
|
||||||
uniform float lightMapMultiplier;
|
uniform float lightMapMultiplier;
|
||||||
|
|
||||||
varying vec2 fragmentTextureCoordinate;
|
in vec2 fragmentTextureCoordinate;
|
||||||
varying float fragmentTextureIndex;
|
flat in int fragmentTextureIndex;
|
||||||
varying vec4 fragmentColor;
|
in vec4 fragmentColor;
|
||||||
varying float fragmentLightMapMultiplier;
|
in float fragmentLightMapMultiplier;
|
||||||
varying vec2 fragmentLightMapCoordinate;
|
in vec2 fragmentLightMapCoordinate;
|
||||||
|
|
||||||
|
out vec4 outColor;
|
||||||
|
|
||||||
vec4 cubic(float v) {
|
vec4 cubic(float v) {
|
||||||
vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v;
|
vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v;
|
||||||
@ -64,15 +66,15 @@ vec3 sampleLight(vec2 coord, vec2 scale) {
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 texColor;
|
vec4 texColor;
|
||||||
if (fragmentTextureIndex > 2.9) {
|
if (fragmentTextureIndex == 3)
|
||||||
texColor = texture2D(texture3, fragmentTextureCoordinate);
|
texColor = texture2D(texture3, fragmentTextureCoordinate);
|
||||||
} else if (fragmentTextureIndex > 1.9) {
|
else if (fragmentTextureIndex == 2)
|
||||||
texColor = texture2D(texture2, fragmentTextureCoordinate);
|
texColor = texture2D(texture2, fragmentTextureCoordinate);
|
||||||
} else if (fragmentTextureIndex > 0.9) {
|
else if (fragmentTextureIndex == 1)
|
||||||
texColor = texture2D(texture1, fragmentTextureCoordinate);
|
texColor = texture2D(texture1, fragmentTextureCoordinate);
|
||||||
} else {
|
else
|
||||||
texColor = texture2D(texture0, fragmentTextureCoordinate);
|
texColor = texture2D(texture0, fragmentTextureCoordinate);
|
||||||
}
|
|
||||||
if (texColor.a <= 0.0)
|
if (texColor.a <= 0.0)
|
||||||
discard;
|
discard;
|
||||||
|
|
||||||
@ -82,5 +84,5 @@ void main() {
|
|||||||
finalColor.a = fragmentColor.a;
|
finalColor.a = fragmentColor.a;
|
||||||
else if (lightMapEnabled && finalLightMapMultiplier > 0.0)
|
else if (lightMapEnabled && finalLightMapMultiplier > 0.0)
|
||||||
finalColor.rgb *= sampleLight(fragmentLightMapCoordinate, 1.0 / lightMapSize) * finalLightMapMultiplier;
|
finalColor.rgb *= sampleLight(fragmentLightMapCoordinate, 1.0 / lightMapSize) * finalLightMapMultiplier;
|
||||||
gl_FragColor = finalColor;
|
outColor = finalColor;
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
#version 110
|
#version 130
|
||||||
|
|
||||||
uniform vec2 textureSize0;
|
uniform vec2 textureSize0;
|
||||||
uniform vec2 textureSize1;
|
uniform vec2 textureSize1;
|
||||||
@ -10,31 +10,37 @@ uniform vec2 lightMapSize;
|
|||||||
uniform vec2 lightMapScale;
|
uniform vec2 lightMapScale;
|
||||||
uniform vec2 lightMapOffset;
|
uniform vec2 lightMapOffset;
|
||||||
|
|
||||||
attribute vec2 vertexPosition;
|
in vec2 vertexPosition;
|
||||||
attribute vec2 vertexTextureCoordinate;
|
in vec2 vertexTextureCoordinate;
|
||||||
attribute float vertexTextureIndex;
|
in vec4 vertexColor;
|
||||||
attribute vec4 vertexColor;
|
in int vertexData;
|
||||||
attribute float vertexParam1;
|
|
||||||
|
|
||||||
varying vec2 fragmentTextureCoordinate;
|
out vec2 fragmentTextureCoordinate;
|
||||||
varying float fragmentTextureIndex;
|
flat out int fragmentTextureIndex;
|
||||||
varying vec4 fragmentColor;
|
out vec4 fragmentColor;
|
||||||
varying float fragmentLightMapMultiplier;
|
out float fragmentLightMapMultiplier;
|
||||||
varying vec2 fragmentLightMapCoordinate;
|
out vec2 fragmentLightMapCoordinate;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 screenPosition = (vertexTransform * vec3(vertexPosition, 1.0)).xy;
|
vec2 screenPosition = (vertexTransform * vec3(vertexPosition, 1.0)).xy;
|
||||||
fragmentLightMapMultiplier = vertexParam1;
|
|
||||||
|
if (((vertexData >> 3) & 0x1) == 1)
|
||||||
|
screenPosition.x = round(screenPosition.x);
|
||||||
|
if (((vertexData >> 4) & 0x1) == 1)
|
||||||
|
screenPosition.y = round(screenPosition.y);
|
||||||
|
|
||||||
|
fragmentLightMapMultiplier = float((vertexData >> 2) & 0x1);
|
||||||
|
int vertexTextureIndex = vertexData & 0x3;
|
||||||
fragmentLightMapCoordinate = (screenPosition / lightMapScale) - lightMapOffset * lightMapSize / screenSize;
|
fragmentLightMapCoordinate = (screenPosition / lightMapScale) - lightMapOffset * lightMapSize / screenSize;
|
||||||
if (vertexTextureIndex > 2.9) {
|
if (vertexTextureIndex == 3)
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize3;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize3;
|
||||||
} else if (vertexTextureIndex > 1.9) {
|
else if (vertexTextureIndex == 2)
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize2;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize2;
|
||||||
} else if (vertexTextureIndex > 0.9) {
|
else if (vertexTextureIndex == 1)
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize1;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize1;
|
||||||
} else {
|
else
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize0;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize0;
|
||||||
}
|
|
||||||
fragmentTextureIndex = vertexTextureIndex;
|
fragmentTextureIndex = vertexTextureIndex;
|
||||||
fragmentColor = vertexColor;
|
fragmentColor = vertexColor;
|
||||||
gl_Position = vec4(screenPosition / screenSize * 2.0 - 1.0, 0.0, 1.0);
|
gl_Position = vec4(screenPosition / screenSize * 2.0 - 1.0, 0.0, 1.0);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"frameBuffers" : {
|
"frameBuffers" : {
|
||||||
"world" : {}
|
"main" : {}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -20,14 +20,14 @@ SET (star_application_SOURCES
|
|||||||
SET (star_application_HEADERS ${star_application_HEADERS}
|
SET (star_application_HEADERS ${star_application_HEADERS}
|
||||||
StarP2PNetworkingService_pc.hpp
|
StarP2PNetworkingService_pc.hpp
|
||||||
StarPlatformServices_pc.hpp
|
StarPlatformServices_pc.hpp
|
||||||
StarRenderer_opengl20.hpp
|
StarRenderer_opengl.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
SET (star_application_SOURCES ${star_application_SOURCES}
|
SET (star_application_SOURCES ${star_application_SOURCES}
|
||||||
StarMainApplication_sdl.cpp
|
StarMainApplication_sdl.cpp
|
||||||
StarP2PNetworkingService_pc.cpp
|
StarP2PNetworkingService_pc.cpp
|
||||||
StarPlatformServices_pc.cpp
|
StarPlatformServices_pc.cpp
|
||||||
StarRenderer_opengl20.cpp
|
StarRenderer_opengl.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
IF (STAR_ENABLE_STEAM_INTEGRATION)
|
IF (STAR_ENABLE_STEAM_INTEGRATION)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include "StarLogging.hpp"
|
#include "StarLogging.hpp"
|
||||||
#include "StarSignalHandler.hpp"
|
#include "StarSignalHandler.hpp"
|
||||||
#include "StarTickRateMonitor.hpp"
|
#include "StarTickRateMonitor.hpp"
|
||||||
#include "StarRenderer_opengl20.hpp"
|
#include "StarRenderer_opengl.hpp"
|
||||||
#include "StarTtlCache.hpp"
|
#include "StarTtlCache.hpp"
|
||||||
#include "StarImage.hpp"
|
#include "StarImage.hpp"
|
||||||
#include "StarImageProcessing.hpp"
|
#include "StarImageProcessing.hpp"
|
||||||
@ -335,7 +335,7 @@ public:
|
|||||||
SDL_PauseAudioDevice(m_sdlAudioOutputDevice, 0);
|
SDL_PauseAudioDevice(m_sdlAudioOutputDevice, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_renderer = make_shared<OpenGl20Renderer>();
|
m_renderer = make_shared<OpenGlRenderer>();
|
||||||
m_renderer->setScreenSize(m_windowSize);
|
m_renderer->setScreenSize(m_windowSize);
|
||||||
|
|
||||||
m_cursorCache.setTimeToLive(30000);
|
m_cursorCache.setTimeToLive(30000);
|
||||||
@ -930,7 +930,7 @@ private:
|
|||||||
bool m_audioEnabled = false;
|
bool m_audioEnabled = false;
|
||||||
bool m_quitRequested = false;
|
bool m_quitRequested = false;
|
||||||
|
|
||||||
OpenGl20RendererPtr m_renderer;
|
OpenGlRendererPtr m_renderer;
|
||||||
ApplicationUPtr m_application;
|
ApplicationUPtr m_application;
|
||||||
PcPlatformServicesUPtr m_platformServices;
|
PcPlatformServicesUPtr m_platformServices;
|
||||||
};
|
};
|
||||||
|
@ -153,6 +153,7 @@ public:
|
|||||||
TextureFiltering filtering = TextureFiltering::Nearest) = 0;
|
TextureFiltering filtering = TextureFiltering::Nearest) = 0;
|
||||||
virtual void setSizeLimitEnabled(bool enabled) = 0;
|
virtual void setSizeLimitEnabled(bool enabled) = 0;
|
||||||
virtual void setMultiTexturingEnabled(bool enabled) = 0;
|
virtual void setMultiTexturingEnabled(bool enabled) = 0;
|
||||||
|
virtual void setMultiSampling(unsigned multiSampling) = 0;
|
||||||
virtual TextureGroupPtr createTextureGroup(TextureGroupSize size = TextureGroupSize::Medium, TextureFiltering filtering = TextureFiltering::Nearest) = 0;
|
virtual TextureGroupPtr createTextureGroup(TextureGroupSize size = TextureGroupSize::Medium, TextureFiltering filtering = TextureFiltering::Nearest) = 0;
|
||||||
virtual RenderBufferPtr createRenderBuffer() = 0;
|
virtual RenderBufferPtr createRenderBuffer() = 0;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "StarRenderer_opengl20.hpp"
|
#include "StarRenderer_opengl.hpp"
|
||||||
#include "StarJsonExtra.hpp"
|
#include "StarJsonExtra.hpp"
|
||||||
#include "StarCasting.hpp"
|
#include "StarCasting.hpp"
|
||||||
#include "StarLogging.hpp"
|
#include "StarLogging.hpp"
|
||||||
@ -8,7 +8,7 @@ namespace Star {
|
|||||||
size_t const MultiTextureCount = 4;
|
size_t const MultiTextureCount = 4;
|
||||||
|
|
||||||
char const* DefaultVertexShader = R"SHADER(
|
char const* DefaultVertexShader = R"SHADER(
|
||||||
#version 110
|
#version 130
|
||||||
|
|
||||||
uniform vec2 textureSize0;
|
uniform vec2 textureSize0;
|
||||||
uniform vec2 textureSize1;
|
uniform vec2 textureSize1;
|
||||||
@ -17,59 +17,70 @@ uniform vec2 textureSize3;
|
|||||||
uniform vec2 screenSize;
|
uniform vec2 screenSize;
|
||||||
uniform mat3 vertexTransform;
|
uniform mat3 vertexTransform;
|
||||||
|
|
||||||
attribute vec2 vertexPosition;
|
in vec2 vertexPosition;
|
||||||
attribute vec2 vertexTextureCoordinate;
|
in vec4 vertexColor;
|
||||||
attribute float vertexTextureIndex;
|
in vec2 vertexTextureCoordinate;
|
||||||
attribute vec4 vertexColor;
|
in int vertexData;
|
||||||
attribute float vertexParam1;
|
|
||||||
|
|
||||||
varying vec2 fragmentTextureCoordinate;
|
out vec2 fragmentTextureCoordinate;
|
||||||
varying float fragmentTextureIndex;
|
flat out int fragmentTextureIndex;
|
||||||
varying vec4 fragmentColor;
|
out vec4 fragmentColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 screenPosition = (vertexTransform * vec3(vertexPosition, 1.0)).xy;
|
vec2 screenPosition = (vertexTransform * vec3(vertexPosition, 1.0)).xy;
|
||||||
gl_Position = vec4(screenPosition / screenSize * 2.0 - 1.0, 0.0, 1.0);
|
gl_Position = vec4(screenPosition / screenSize * 2.0 - 1.0, 0.0, 1.0);
|
||||||
if (vertexTextureIndex > 2.9) {
|
if (((vertexData >> 3) & 0x1) == 1)
|
||||||
|
screenPosition.x = round(screenPosition.x);
|
||||||
|
if (((vertexData >> 4) & 0x1) == 1)
|
||||||
|
screenPosition.y = round(screenPosition.y);
|
||||||
|
int vertexTextureIndex = vertexData & 0x3;
|
||||||
|
if (vertexTextureIndex == 3)
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize3;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize3;
|
||||||
} else if (vertexTextureIndex > 1.9) {
|
else if (vertexTextureIndex == 2)
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize2;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize2;
|
||||||
} else if (vertexTextureIndex > 0.9) {
|
else if (vertexTextureIndex == 1)
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize1;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize1;
|
||||||
} else {
|
else
|
||||||
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize0;
|
fragmentTextureCoordinate = vertexTextureCoordinate / textureSize0;
|
||||||
}
|
|
||||||
fragmentTextureIndex = vertexTextureIndex;
|
fragmentTextureIndex = vertexTextureIndex;
|
||||||
fragmentColor = vertexColor;
|
fragmentColor = vertexColor;
|
||||||
}
|
}
|
||||||
)SHADER";
|
)SHADER";
|
||||||
|
|
||||||
char const* DefaultFragmentShader = R"SHADER(
|
char const* DefaultFragmentShader = R"SHADER(
|
||||||
#version 110
|
#version 130
|
||||||
|
|
||||||
uniform sampler2D texture0;
|
uniform sampler2D texture0;
|
||||||
uniform sampler2D texture1;
|
uniform sampler2D texture1;
|
||||||
uniform sampler2D texture2;
|
uniform sampler2D texture2;
|
||||||
uniform sampler2D texture3;
|
uniform sampler2D texture3;
|
||||||
|
|
||||||
varying vec2 fragmentTextureCoordinate;
|
in vec2 fragmentTextureCoordinate;
|
||||||
varying float fragmentTextureIndex;
|
flat in int fragmentTextureIndex;
|
||||||
varying vec4 fragmentColor;
|
in vec4 fragmentColor;
|
||||||
|
|
||||||
|
out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
if (fragmentTextureIndex > 2.9) {
|
vec4 texColor;
|
||||||
gl_FragColor = texture2D(texture3, fragmentTextureCoordinate) * fragmentColor;
|
if (fragmentTextureIndex == 3)
|
||||||
} else if (fragmentTextureIndex > 1.9) {
|
texColor = texture2D(texture3, fragmentTextureCoordinate);
|
||||||
gl_FragColor = texture2D(texture2, fragmentTextureCoordinate) * fragmentColor;
|
else if (fragmentTextureIndex == 2)
|
||||||
} else if (fragmentTextureIndex > 0.9) {
|
texColor = texture2D(texture2, fragmentTextureCoordinate);
|
||||||
gl_FragColor = texture2D(texture1, fragmentTextureCoordinate) * fragmentColor;
|
else if (fragmentTextureIndex == 1)
|
||||||
} else {
|
texColor = texture2D(texture1, fragmentTextureCoordinate);
|
||||||
gl_FragColor = texture2D(texture0, fragmentTextureCoordinate) * fragmentColor;
|
else
|
||||||
}
|
texColor = texture2D(texture0, fragmentTextureCoordinate);
|
||||||
|
|
||||||
|
if (texColor.a <= 0.0)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
outColor = texColor * fragmentColor;
|
||||||
}
|
}
|
||||||
)SHADER";
|
)SHADER";
|
||||||
|
|
||||||
OpenGl20Renderer::OpenGl20Renderer() {
|
OpenGlRenderer::OpenGlRenderer() {
|
||||||
if (glewInit() != GLEW_OK)
|
if (glewInit() != GLEW_OK)
|
||||||
throw RendererException("Could not initialize GLEW");
|
throw RendererException("Could not initialize GLEW");
|
||||||
|
|
||||||
@ -97,11 +108,12 @@ OpenGl20Renderer::OpenGl20Renderer() {
|
|||||||
|
|
||||||
m_limitTextureGroupSize = false;
|
m_limitTextureGroupSize = false;
|
||||||
m_useMultiTexturing = true;
|
m_useMultiTexturing = true;
|
||||||
|
m_multiSampling = false;
|
||||||
|
|
||||||
logGlErrorSummary("OpenGL errors during renderer initialization");
|
logGlErrorSummary("OpenGL errors during renderer initialization");
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGl20Renderer::~OpenGl20Renderer() {
|
OpenGlRenderer::~OpenGlRenderer() {
|
||||||
for (auto& effect : m_effects)
|
for (auto& effect : m_effects)
|
||||||
glDeleteProgram(effect.second.program);
|
glDeleteProgram(effect.second.program);
|
||||||
|
|
||||||
@ -109,27 +121,40 @@ OpenGl20Renderer::~OpenGl20Renderer() {
|
|||||||
logGlErrorSummary("OpenGL errors during shutdown");
|
logGlErrorSummary("OpenGL errors during shutdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
String OpenGl20Renderer::rendererId() const {
|
String OpenGlRenderer::rendererId() const {
|
||||||
return "OpenGL20";
|
return "OpenGL20";
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2U OpenGl20Renderer::screenSize() const {
|
Vec2U OpenGlRenderer::screenSize() const {
|
||||||
return m_screenSize;
|
return m_screenSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGl20Renderer::GlFrameBuffer::GlFrameBuffer(Json const& fbConfig) : config(fbConfig) {
|
OpenGlRenderer::GlFrameBuffer::GlFrameBuffer(Json const& fbConfig) : config(fbConfig) {
|
||||||
texture = createGlTexture(ImageView(), TextureAddressing::Clamp, TextureFiltering::Nearest);
|
texture = make_ref<GlLoneTexture>();
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->glTextureId());
|
texture->textureFiltering = TextureFiltering::Nearest;
|
||||||
|
texture->textureAddressing = TextureAddressing::Clamp;
|
||||||
|
texture->textureSize = {0, 0};
|
||||||
|
glGenTextures(1, &texture->textureId);
|
||||||
|
if (texture->textureId == 0)
|
||||||
|
throw RendererException("Could not generate OpenGL texture for framebuffer");
|
||||||
|
|
||||||
|
multisample = GLEW_VERSION_4_0 ? config.getUInt("multisample", 0) : 0;
|
||||||
|
GLenum target = multisample ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
|
||||||
|
glBindTexture(target, texture->glTextureId());
|
||||||
|
|
||||||
Vec2U size = jsonToVec2U(config.getArray("size", { 256, 256 }));
|
Vec2U size = jsonToVec2U(config.getArray("size", { 256, 256 }));
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size[0] , size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
|
||||||
|
if (multisample)
|
||||||
|
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, multisample, GL_RGBA8, size[0], size[1], GL_TRUE);
|
||||||
|
else
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size[0], size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
glGenFramebuffers(1, &id);
|
glGenFramebuffers(1, &id);
|
||||||
if (!id)
|
if (!id)
|
||||||
throw RendererException("Failed to create OpenGL framebuffer");
|
throw RendererException("Failed to create OpenGL framebuffer");
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, id);
|
glBindFramebuffer(GL_FRAMEBUFFER, id);
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->glTextureId(), 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, texture->glTextureId(), 0);
|
||||||
|
|
||||||
auto framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
auto framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE)
|
if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE)
|
||||||
@ -137,21 +162,25 @@ OpenGl20Renderer::GlFrameBuffer::GlFrameBuffer(Json const& fbConfig) : config(fb
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OpenGl20Renderer::GlFrameBuffer::~GlFrameBuffer() {
|
OpenGlRenderer::GlFrameBuffer::~GlFrameBuffer() {
|
||||||
glDeleteFramebuffers(1, &id);
|
glDeleteFramebuffers(1, &id);
|
||||||
texture.reset();
|
texture.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::loadConfig(Json const& config) {
|
void OpenGlRenderer::loadConfig(Json const& config) {
|
||||||
m_frameBuffers.clear();
|
m_frameBuffers.clear();
|
||||||
|
|
||||||
for (auto& pair : config.getObject("frameBuffers", {}))
|
for (auto& pair : config.getObject("frameBuffers", {})) {
|
||||||
m_frameBuffers[pair.first] = make_ref<GlFrameBuffer>(pair.second);
|
Json config = pair.second;
|
||||||
|
config = config.set("multisample", m_multiSampling);
|
||||||
|
m_frameBuffers[pair.first] = make_ref<GlFrameBuffer>(config);
|
||||||
|
|
||||||
|
}
|
||||||
setScreenSize(m_screenSize);
|
setScreenSize(m_screenSize);
|
||||||
|
m_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::loadEffectConfig(String const& name, Json const& effectConfig, StringMap<String> const& shaders) {
|
void OpenGlRenderer::loadEffectConfig(String const& name, Json const& effectConfig, StringMap<String> const& shaders) {
|
||||||
if (auto effect = m_effects.ptr(name)) {
|
if (auto effect = m_effects.ptr(name)) {
|
||||||
Logger::info("Reloading OpenGL effect {}", name);
|
Logger::info("Reloading OpenGL effect {}", name);
|
||||||
glDeleteProgram(effect->program);
|
glDeleteProgram(effect->program);
|
||||||
@ -294,13 +323,13 @@ void OpenGl20Renderer::loadEffectConfig(String const& name, Json const& effectCo
|
|||||||
logGlErrorSummary("OpenGL errors setting effect config");
|
logGlErrorSummary("OpenGL errors setting effect config");
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::setEffectParameter(String const& parameterName, RenderEffectParameter const& value) {
|
void OpenGlRenderer::setEffectParameter(String const& parameterName, RenderEffectParameter const& value) {
|
||||||
auto ptr = m_currentEffect->parameters.ptr(parameterName);
|
auto ptr = m_currentEffect->parameters.ptr(parameterName);
|
||||||
if (!ptr || (ptr->parameterValue && *ptr->parameterValue == value))
|
if (!ptr || (ptr->parameterValue && *ptr->parameterValue == value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ptr->parameterType != value.typeIndex())
|
if (ptr->parameterType != value.typeIndex())
|
||||||
throw RendererException::format("OpenGL20Renderer::setEffectParameter '{}' parameter type mismatch", parameterName);
|
throw RendererException::format("OpenGlRenderer::setEffectParameter '{}' parameter type mismatch", parameterName);
|
||||||
|
|
||||||
flushImmediatePrimitives();
|
flushImmediatePrimitives();
|
||||||
|
|
||||||
@ -320,7 +349,7 @@ void OpenGl20Renderer::setEffectParameter(String const& parameterName, RenderEff
|
|||||||
ptr->parameterValue = value;
|
ptr->parameterValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::setEffectTexture(String const& textureName, ImageView const& image) {
|
void OpenGlRenderer::setEffectTexture(String const& textureName, ImageView const& image) {
|
||||||
auto ptr = m_currentEffect->textures.ptr(textureName);
|
auto ptr = m_currentEffect->textures.ptr(textureName);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
return;
|
return;
|
||||||
@ -341,7 +370,7 @@ void OpenGl20Renderer::setEffectTexture(String const& textureName, ImageView con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGl20Renderer::switchEffectConfig(String const& name) {
|
bool OpenGlRenderer::switchEffectConfig(String const& name) {
|
||||||
flushImmediatePrimitives();
|
flushImmediatePrimitives();
|
||||||
auto find = m_effects.find(name);
|
auto find = m_effects.find(name);
|
||||||
if (find == m_effects.end())
|
if (find == m_effects.end())
|
||||||
@ -368,7 +397,7 @@ bool OpenGl20Renderer::switchEffectConfig(String const& name) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::setScissorRect(Maybe<RectI> const& scissorRect) {
|
void OpenGlRenderer::setScissorRect(Maybe<RectI> const& scissorRect) {
|
||||||
if (scissorRect == m_scissorRect)
|
if (scissorRect == m_scissorRect)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -383,22 +412,39 @@ void OpenGl20Renderer::setScissorRect(Maybe<RectI> const& scissorRect) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TexturePtr OpenGl20Renderer::createTexture(Image const& texture, TextureAddressing addressing, TextureFiltering filtering) {
|
TexturePtr OpenGlRenderer::createTexture(Image const& texture, TextureAddressing addressing, TextureFiltering filtering) {
|
||||||
return createGlTexture(texture, addressing, filtering);
|
return createGlTexture(texture, addressing, filtering);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::setSizeLimitEnabled(bool enabled) {
|
void OpenGlRenderer::setSizeLimitEnabled(bool enabled) {
|
||||||
m_limitTextureGroupSize = enabled;
|
m_limitTextureGroupSize = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::setMultiTexturingEnabled(bool enabled) {
|
void OpenGlRenderer::setMultiTexturingEnabled(bool enabled) {
|
||||||
m_useMultiTexturing = enabled;
|
m_useMultiTexturing = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureGroupPtr OpenGl20Renderer::createTextureGroup(TextureGroupSize textureSize, TextureFiltering filtering) {
|
void OpenGlRenderer::setMultiSampling(unsigned multiSampling) {
|
||||||
|
if (m_multiSampling == multiSampling)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_multiSampling = multiSampling;
|
||||||
|
if (m_multiSampling) {
|
||||||
|
glEnable(GL_MULTISAMPLE);
|
||||||
|
glEnable(GL_SAMPLE_SHADING);
|
||||||
|
glMinSampleShading((float)m_multiSampling);
|
||||||
|
} else {
|
||||||
|
glMinSampleShading(1.f);
|
||||||
|
glDisable(GL_SAMPLE_SHADING);
|
||||||
|
glDisable(GL_MULTISAMPLE);
|
||||||
|
}
|
||||||
|
loadConfig(m_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureGroupPtr OpenGlRenderer::createTextureGroup(TextureGroupSize textureSize, TextureFiltering filtering) {
|
||||||
int maxTextureSize;
|
int maxTextureSize;
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
|
||||||
|
maxTextureSize = min(maxTextureSize, (2 << 14));
|
||||||
// Large texture sizes are not always supported
|
// Large texture sizes are not always supported
|
||||||
if (textureSize == TextureGroupSize::Large && (m_limitTextureGroupSize || maxTextureSize < 4096))
|
if (textureSize == TextureGroupSize::Large && (m_limitTextureGroupSize || maxTextureSize < 4096))
|
||||||
textureSize = TextureGroupSize::Medium;
|
textureSize = TextureGroupSize::Medium;
|
||||||
@ -419,39 +465,44 @@ TextureGroupPtr OpenGl20Renderer::createTextureGroup(TextureGroupSize textureSiz
|
|||||||
return glTextureGroup;
|
return glTextureGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderBufferPtr OpenGl20Renderer::createRenderBuffer() {
|
RenderBufferPtr OpenGlRenderer::createRenderBuffer() {
|
||||||
return createGlRenderBuffer();
|
return createGlRenderBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RenderPrimitive>& OpenGl20Renderer::immediatePrimitives() {
|
List<RenderPrimitive>& OpenGlRenderer::immediatePrimitives() {
|
||||||
return m_immediatePrimitives;
|
return m_immediatePrimitives;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::render(RenderPrimitive primitive) {
|
void OpenGlRenderer::render(RenderPrimitive primitive) {
|
||||||
m_immediatePrimitives.append(std::move(primitive));
|
m_immediatePrimitives.append(std::move(primitive));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::renderBuffer(RenderBufferPtr const& renderBuffer, Mat3F const& transformation) {
|
void OpenGlRenderer::renderBuffer(RenderBufferPtr const& renderBuffer, Mat3F const& transformation) {
|
||||||
flushImmediatePrimitives();
|
flushImmediatePrimitives();
|
||||||
renderGlBuffer(*convert<GlRenderBuffer>(renderBuffer.get()), transformation);
|
renderGlBuffer(*convert<GlRenderBuffer>(renderBuffer.get()), transformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::flush() {
|
void OpenGlRenderer::flush() {
|
||||||
flushImmediatePrimitives();
|
flushImmediatePrimitives();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::setScreenSize(Vec2U screenSize) {
|
void OpenGlRenderer::setScreenSize(Vec2U screenSize) {
|
||||||
m_screenSize = screenSize;
|
m_screenSize = screenSize;
|
||||||
glViewport(0, 0, m_screenSize[0], m_screenSize[1]);
|
glViewport(0, 0, m_screenSize[0], m_screenSize[1]);
|
||||||
glUniform2f(m_screenSizeUniform, m_screenSize[0], m_screenSize[1]);
|
glUniform2f(m_screenSizeUniform, m_screenSize[0], m_screenSize[1]);
|
||||||
|
|
||||||
for (auto& frameBuffer : m_frameBuffers) {
|
for (auto& frameBuffer : m_frameBuffers) {
|
||||||
glBindTexture(GL_TEXTURE_2D, frameBuffer.second->texture->glTextureId());
|
if (unsigned multisample = frameBuffer.second->multisample) {
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_screenSize[0], m_screenSize[1], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, frameBuffer.second->texture->glTextureId());
|
||||||
|
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, multisample, GL_RGBA8, m_screenSize[0], m_screenSize[1], GL_TRUE);
|
||||||
|
} else {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, frameBuffer.second->texture->glTextureId());
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_screenSize[0], m_screenSize[1], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::startFrame() {
|
void OpenGlRenderer::startFrame() {
|
||||||
if (m_scissorRect)
|
if (m_scissorRect)
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
|
||||||
@ -469,7 +520,7 @@ void OpenGl20Renderer::startFrame() {
|
|||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::finishFrame() {
|
void OpenGlRenderer::finishFrame() {
|
||||||
flushImmediatePrimitives();
|
flushImmediatePrimitives();
|
||||||
// Make sure that the immediate render buffer doesn't needlessly lock texutres
|
// Make sure that the immediate render buffer doesn't needlessly lock texutres
|
||||||
// from being compressed.
|
// from being compressed.
|
||||||
@ -494,14 +545,14 @@ void OpenGl20Renderer::finishFrame() {
|
|||||||
logGlErrorSummary("OpenGL errors this frame");
|
logGlErrorSummary("OpenGL errors this frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGl20Renderer::GlTextureAtlasSet::GlTextureAtlasSet(unsigned atlasNumCells)
|
OpenGlRenderer::GlTextureAtlasSet::GlTextureAtlasSet(unsigned atlasNumCells)
|
||||||
: TextureAtlasSet(16, atlasNumCells) {}
|
: TextureAtlasSet(16, atlasNumCells) {}
|
||||||
|
|
||||||
GLuint OpenGl20Renderer::GlTextureAtlasSet::createAtlasTexture(Vec2U const& size, PixelFormat pixelFormat) {
|
GLuint OpenGlRenderer::GlTextureAtlasSet::createAtlasTexture(Vec2U const& size, PixelFormat pixelFormat) {
|
||||||
GLuint glTextureId;
|
GLuint glTextureId;
|
||||||
glGenTextures(1, &glTextureId);
|
glGenTextures(1, &glTextureId);
|
||||||
if (glTextureId == 0)
|
if (glTextureId == 0)
|
||||||
throw RendererException("Could not generate texture in OpenGL20Renderer::TextureGroup::createAtlasTexture()");
|
throw RendererException("Could not generate texture in OpenGlRenderer::TextureGroup::createAtlasTexture()");
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, glTextureId);
|
glBindTexture(GL_TEXTURE_2D, glTextureId);
|
||||||
|
|
||||||
@ -520,11 +571,11 @@ GLuint OpenGl20Renderer::GlTextureAtlasSet::createAtlasTexture(Vec2U const& size
|
|||||||
return glTextureId;
|
return glTextureId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::GlTextureAtlasSet::destroyAtlasTexture(GLuint const& glTexture) {
|
void OpenGlRenderer::GlTextureAtlasSet::destroyAtlasTexture(GLuint const& glTexture) {
|
||||||
glDeleteTextures(1, &glTexture);
|
glDeleteTextures(1, &glTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::GlTextureAtlasSet::copyAtlasPixels(
|
void OpenGlRenderer::GlTextureAtlasSet::copyAtlasPixels(
|
||||||
GLuint const& glTexture, Vec2U const& bottomLeft, Image const& image) {
|
GLuint const& glTexture, Vec2U const& bottomLeft, Image const& image) {
|
||||||
glBindTexture(GL_TEXTURE_2D, glTexture);
|
glBindTexture(GL_TEXTURE_2D, glTexture);
|
||||||
|
|
||||||
@ -540,23 +591,23 @@ void OpenGl20Renderer::GlTextureAtlasSet::copyAtlasPixels(
|
|||||||
else if (pixelFormat == PixelFormat::BGRA32)
|
else if (pixelFormat == PixelFormat::BGRA32)
|
||||||
format = GL_BGRA;
|
format = GL_BGRA;
|
||||||
else
|
else
|
||||||
throw RendererException("Unsupported texture format in OpenGL20Renderer::TextureGroup::copyAtlasPixels");
|
throw RendererException("Unsupported texture format in OpenGlRenderer::TextureGroup::copyAtlasPixels");
|
||||||
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), format, GL_UNSIGNED_BYTE, image.data());
|
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), format, GL_UNSIGNED_BYTE, image.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGl20Renderer::GlTextureGroup::GlTextureGroup(unsigned atlasNumCells)
|
OpenGlRenderer::GlTextureGroup::GlTextureGroup(unsigned atlasNumCells)
|
||||||
: textureAtlasSet(atlasNumCells) {}
|
: textureAtlasSet(atlasNumCells) {}
|
||||||
|
|
||||||
OpenGl20Renderer::GlTextureGroup::~GlTextureGroup() {
|
OpenGlRenderer::GlTextureGroup::~GlTextureGroup() {
|
||||||
textureAtlasSet.reset();
|
textureAtlasSet.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureFiltering OpenGl20Renderer::GlTextureGroup::filtering() const {
|
TextureFiltering OpenGlRenderer::GlTextureGroup::filtering() const {
|
||||||
return textureAtlasSet.textureFiltering;
|
return textureAtlasSet.textureFiltering;
|
||||||
}
|
}
|
||||||
|
|
||||||
TexturePtr OpenGl20Renderer::GlTextureGroup::create(Image const& texture) {
|
TexturePtr OpenGlRenderer::GlTextureGroup::create(Image const& texture) {
|
||||||
// If the image is empty, or would not fit in the texture atlas with border
|
// If the image is empty, or would not fit in the texture atlas with border
|
||||||
// pixels, just create a regular texture
|
// pixels, just create a regular texture
|
||||||
Vec2U atlasTextureSize = textureAtlasSet.atlasTextureSize();
|
Vec2U atlasTextureSize = textureAtlasSet.atlasTextureSize();
|
||||||
@ -570,78 +621,78 @@ TexturePtr OpenGl20Renderer::GlTextureGroup::create(Image const& texture) {
|
|||||||
return glGroupedTexture;
|
return glGroupedTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGl20Renderer::GlGroupedTexture::~GlGroupedTexture() {
|
OpenGlRenderer::GlGroupedTexture::~GlGroupedTexture() {
|
||||||
if (parentAtlasTexture)
|
if (parentAtlasTexture)
|
||||||
parentGroup->textureAtlasSet.freeTexture(parentAtlasTexture);
|
parentGroup->textureAtlasSet.freeTexture(parentAtlasTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2U OpenGl20Renderer::GlGroupedTexture::size() const {
|
Vec2U OpenGlRenderer::GlGroupedTexture::size() const {
|
||||||
return parentAtlasTexture->imageSize();
|
return parentAtlasTexture->imageSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureFiltering OpenGl20Renderer::GlGroupedTexture::filtering() const {
|
TextureFiltering OpenGlRenderer::GlGroupedTexture::filtering() const {
|
||||||
return parentGroup->filtering();
|
return parentGroup->filtering();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureAddressing OpenGl20Renderer::GlGroupedTexture::addressing() const {
|
TextureAddressing OpenGlRenderer::GlGroupedTexture::addressing() const {
|
||||||
return TextureAddressing::Clamp;
|
return TextureAddressing::Clamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint OpenGl20Renderer::GlGroupedTexture::glTextureId() const {
|
GLuint OpenGlRenderer::GlGroupedTexture::glTextureId() const {
|
||||||
return parentAtlasTexture->atlasTexture();
|
return parentAtlasTexture->atlasTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2U OpenGl20Renderer::GlGroupedTexture::glTextureSize() const {
|
Vec2U OpenGlRenderer::GlGroupedTexture::glTextureSize() const {
|
||||||
return parentGroup->textureAtlasSet.atlasTextureSize();
|
return parentGroup->textureAtlasSet.atlasTextureSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2U OpenGl20Renderer::GlGroupedTexture::glTextureCoordinateOffset() const {
|
Vec2U OpenGlRenderer::GlGroupedTexture::glTextureCoordinateOffset() const {
|
||||||
return parentAtlasTexture->atlasTextureCoordinates().min();
|
return parentAtlasTexture->atlasTextureCoordinates().min();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::GlGroupedTexture::incrementBufferUseCount() {
|
void OpenGlRenderer::GlGroupedTexture::incrementBufferUseCount() {
|
||||||
if (bufferUseCount == 0)
|
if (bufferUseCount == 0)
|
||||||
parentAtlasTexture->setLocked(true);
|
parentAtlasTexture->setLocked(true);
|
||||||
++bufferUseCount;
|
++bufferUseCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::GlGroupedTexture::decrementBufferUseCount() {
|
void OpenGlRenderer::GlGroupedTexture::decrementBufferUseCount() {
|
||||||
starAssert(bufferUseCount != 0);
|
starAssert(bufferUseCount != 0);
|
||||||
if (bufferUseCount == 1)
|
if (bufferUseCount == 1)
|
||||||
parentAtlasTexture->setLocked(false);
|
parentAtlasTexture->setLocked(false);
|
||||||
--bufferUseCount;
|
--bufferUseCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGl20Renderer::GlLoneTexture::~GlLoneTexture() {
|
OpenGlRenderer::GlLoneTexture::~GlLoneTexture() {
|
||||||
if (textureId != 0)
|
if (textureId != 0)
|
||||||
glDeleteTextures(1, &textureId);
|
glDeleteTextures(1, &textureId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2U OpenGl20Renderer::GlLoneTexture::size() const {
|
Vec2U OpenGlRenderer::GlLoneTexture::size() const {
|
||||||
return textureSize;
|
return textureSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureFiltering OpenGl20Renderer::GlLoneTexture::filtering() const {
|
TextureFiltering OpenGlRenderer::GlLoneTexture::filtering() const {
|
||||||
return textureFiltering;
|
return textureFiltering;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureAddressing OpenGl20Renderer::GlLoneTexture::addressing() const {
|
TextureAddressing OpenGlRenderer::GlLoneTexture::addressing() const {
|
||||||
return textureAddressing;
|
return textureAddressing;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint OpenGl20Renderer::GlLoneTexture::glTextureId() const {
|
GLuint OpenGlRenderer::GlLoneTexture::glTextureId() const {
|
||||||
return textureId;
|
return textureId;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2U OpenGl20Renderer::GlLoneTexture::glTextureSize() const {
|
Vec2U OpenGlRenderer::GlLoneTexture::glTextureSize() const {
|
||||||
return textureSize;
|
return textureSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2U OpenGl20Renderer::GlLoneTexture::glTextureCoordinateOffset() const {
|
Vec2U OpenGlRenderer::GlLoneTexture::glTextureCoordinateOffset() const {
|
||||||
return Vec2U();
|
return Vec2U();
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGl20Renderer::GlRenderBuffer::~GlRenderBuffer() {
|
OpenGlRenderer::GlRenderBuffer::~GlRenderBuffer() {
|
||||||
for (auto const& texture : usedTextures) {
|
for (auto const& texture : usedTextures) {
|
||||||
if (auto gt = as<GlGroupedTexture>(texture.get()))
|
if (auto gt = as<GlGroupedTexture>(texture.get()))
|
||||||
gt->decrementBufferUseCount();
|
gt->decrementBufferUseCount();
|
||||||
@ -650,7 +701,7 @@ OpenGl20Renderer::GlRenderBuffer::~GlRenderBuffer() {
|
|||||||
glDeleteBuffers(1, &vb.vertexBuffer);
|
glDeleteBuffers(1, &vb.vertexBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
void OpenGlRenderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
||||||
for (auto const& texture : usedTextures) {
|
for (auto const& texture : usedTextures) {
|
||||||
if (auto gt = as<GlGroupedTexture>(texture.get()))
|
if (auto gt = as<GlGroupedTexture>(texture.get()))
|
||||||
gt->decrementBufferUseCount();
|
gt->decrementBufferUseCount();
|
||||||
@ -718,47 +769,58 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
|||||||
return {float(textureIndex), Vec2F(glTexture->glTextureCoordinateOffset())};
|
return {float(textureIndex), Vec2F(glTexture->glTextureCoordinateOffset())};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto appendBufferVertex = [&](RenderVertex const& v, float textureIndex, Vec2F textureCoordinateOffset) {
|
auto appendBufferVertex = [&](RenderVertex const& v, uint8_t textureIndex, Vec2F textureCoordinateOffset, RenderVertex const& prev, RenderVertex const& next) {
|
||||||
GlRenderVertex glv {
|
size_t off = accumulationBuffer.size();
|
||||||
v.screenCoordinate,
|
accumulationBuffer.resize(accumulationBuffer.size() + sizeof(GlRenderVertex));
|
||||||
v.textureCoordinate + textureCoordinateOffset,
|
GlRenderVertex& glv = *(GlRenderVertex*)(accumulationBuffer.ptr() + off);
|
||||||
textureIndex,
|
glv.pos = v.screenCoordinate;
|
||||||
v.color,
|
glv.uv = v.textureCoordinate + textureCoordinateOffset;
|
||||||
v.param1
|
glv.color = v.color;
|
||||||
};
|
glv.pack.vars.textureIndex = textureIndex;
|
||||||
accumulationBuffer.append((char const*)&glv, sizeof(GlRenderVertex));
|
glv.pack.vars.fullbright = v.param1 > 0.0f;
|
||||||
|
// Tell the vertex shader to round to the nearest pixel if the vertices form a straight
|
||||||
|
// edge, to ensure sharpness with supersampling. If we rounded *all* vertex positions,
|
||||||
|
// it'd cause slight visual issues with sprites rotating around a point.
|
||||||
|
glv.pack.vars.rX = min(abs(glv.pos.x() - prev.screenCoordinate.x()), abs(glv.pos.x() - next.screenCoordinate.x())) < 0.001f;
|
||||||
|
glv.pack.vars.rY = min(abs(glv.pos.y() - prev.screenCoordinate.y()), abs(glv.pos.y() - next.screenCoordinate.y())) < 0.001f;
|
||||||
|
glv.pack.vars.unused = 0;
|
||||||
++currentVertexCount;
|
++currentVertexCount;
|
||||||
|
return glv;
|
||||||
};
|
};
|
||||||
|
|
||||||
float textureIndex = 0.0f;
|
uint8_t textureIndex = 0;
|
||||||
Vec2F textureOffset = {};
|
Vec2F textureOffset = {};
|
||||||
for (auto& primitive : primitives) {
|
for (auto& primitive : primitives) {
|
||||||
if (auto tri = primitive.ptr<RenderTriangle>()) {
|
if (auto tri = primitive.ptr<RenderTriangle>()) {
|
||||||
tie(textureIndex, textureOffset) = addCurrentTexture(std::move(tri->texture));
|
tie(textureIndex, textureOffset) = addCurrentTexture(std::move(tri->texture));
|
||||||
|
|
||||||
appendBufferVertex(tri->a, textureIndex, textureOffset);
|
appendBufferVertex(tri->a, textureIndex, textureOffset, tri->c, tri->b);
|
||||||
appendBufferVertex(tri->b, textureIndex, textureOffset);
|
appendBufferVertex(tri->b, textureIndex, textureOffset, tri->a, tri->c);
|
||||||
appendBufferVertex(tri->c, textureIndex, textureOffset);
|
appendBufferVertex(tri->c, textureIndex, textureOffset, tri->b, tri->a);
|
||||||
|
|
||||||
} else if (auto quad = primitive.ptr<RenderQuad>()) {
|
} else if (auto quad = primitive.ptr<RenderQuad>()) {
|
||||||
tie(textureIndex, textureOffset) = addCurrentTexture(std::move(quad->texture));
|
tie(textureIndex, textureOffset) = addCurrentTexture(std::move(quad->texture));
|
||||||
|
|
||||||
appendBufferVertex(quad->a, textureIndex, textureOffset);
|
// = prev and next are altered - the diagonal across the quad is bad for the rounding check
|
||||||
appendBufferVertex(quad->b, textureIndex, textureOffset);
|
appendBufferVertex(quad->a, textureIndex, textureOffset, quad->d, quad->b);
|
||||||
appendBufferVertex(quad->c, textureIndex, textureOffset);
|
appendBufferVertex(quad->b, textureIndex, textureOffset, quad->a, quad->c); //
|
||||||
|
appendBufferVertex(quad->c, textureIndex, textureOffset, quad->b, quad->d);
|
||||||
|
|
||||||
appendBufferVertex(quad->a, textureIndex, textureOffset);
|
appendBufferVertex(quad->a, textureIndex, textureOffset, quad->d, quad->b);
|
||||||
appendBufferVertex(quad->c, textureIndex, textureOffset);
|
appendBufferVertex(quad->c, textureIndex, textureOffset, quad->b, quad->d); //
|
||||||
appendBufferVertex(quad->d, textureIndex, textureOffset);
|
appendBufferVertex(quad->d, textureIndex, textureOffset, quad->c, quad->a);
|
||||||
|
|
||||||
} else if (auto poly = primitive.ptr<RenderPoly>()) {
|
} else if (auto poly = primitive.ptr<RenderPoly>()) {
|
||||||
if (poly->vertexes.size() > 2) {
|
if (poly->vertexes.size() > 2) {
|
||||||
tie(textureIndex, textureOffset) = addCurrentTexture(std::move(poly->texture));
|
tie(textureIndex, textureOffset) = addCurrentTexture(std::move(poly->texture));
|
||||||
|
|
||||||
for (size_t i = 1; i < poly->vertexes.size() - 1; ++i) {
|
for (size_t i = 1; i < poly->vertexes.size() - 1; ++i) {
|
||||||
appendBufferVertex(poly->vertexes[0], textureIndex, textureOffset);
|
RenderVertex const& a = poly->vertexes[0],
|
||||||
appendBufferVertex(poly->vertexes[i], textureIndex, textureOffset);
|
b = poly->vertexes[i],
|
||||||
appendBufferVertex(poly->vertexes[i + 1], textureIndex, textureOffset);
|
c = poly->vertexes[i + 1];
|
||||||
|
appendBufferVertex(a, textureIndex, textureOffset, c, b);
|
||||||
|
appendBufferVertex(b, textureIndex, textureOffset, a, c);
|
||||||
|
appendBufferVertex(c, textureIndex, textureOffset, b, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -771,7 +833,7 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
|||||||
glDeleteBuffers(1, &vb.vertexBuffer);
|
glDeleteBuffers(1, &vb.vertexBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGl20Renderer::logGlErrorSummary(String prefix) {
|
bool OpenGlRenderer::logGlErrorSummary(String prefix) {
|
||||||
if (GLenum error = glGetError()) {
|
if (GLenum error = glGetError()) {
|
||||||
Logger::error("{}: ", prefix);
|
Logger::error("{}: ", prefix);
|
||||||
do {
|
do {
|
||||||
@ -798,7 +860,7 @@ bool OpenGl20Renderer::logGlErrorSummary(String prefix) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::uploadTextureImage(PixelFormat pixelFormat, Vec2U size, uint8_t const* data) {
|
void OpenGlRenderer::uploadTextureImage(PixelFormat pixelFormat, Vec2U size, uint8_t const* data) {
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
Maybe<GLenum> internalFormat;
|
Maybe<GLenum> internalFormat;
|
||||||
@ -821,13 +883,13 @@ void OpenGl20Renderer::uploadTextureImage(PixelFormat pixelFormat, Vec2U size, u
|
|||||||
internalFormat = GL_RGBA32F;
|
internalFormat = GL_RGBA32F;
|
||||||
format = GL_RGBA;
|
format = GL_RGBA;
|
||||||
} else
|
} else
|
||||||
throw RendererException("Unsupported texture format in OpenGL20Renderer::uploadTextureImage");
|
throw RendererException("Unsupported texture format in OpenGlRenderer::uploadTextureImage");
|
||||||
}
|
}
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat.value(format), size[0], size[1], 0, format, type, data);
|
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat.value(format), size[0], size[1], 0, format, type, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::flushImmediatePrimitives() {
|
void OpenGlRenderer::flushImmediatePrimitives() {
|
||||||
if (m_immediatePrimitives.empty())
|
if (m_immediatePrimitives.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -836,7 +898,7 @@ void OpenGl20Renderer::flushImmediatePrimitives() {
|
|||||||
renderGlBuffer(*m_immediateRenderBuffer, Mat3F::identity());
|
renderGlBuffer(*m_immediateRenderBuffer, Mat3F::identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto OpenGl20Renderer::createGlTexture(ImageView const& image, TextureAddressing addressing, TextureFiltering filtering)
|
auto OpenGlRenderer::createGlTexture(ImageView const& image, TextureAddressing addressing, TextureFiltering filtering)
|
||||||
->RefPtr<GlLoneTexture> {
|
->RefPtr<GlLoneTexture> {
|
||||||
auto glLoneTexture = make_ref<GlLoneTexture>();
|
auto glLoneTexture = make_ref<GlLoneTexture>();
|
||||||
glLoneTexture->textureFiltering = filtering;
|
glLoneTexture->textureFiltering = filtering;
|
||||||
@ -845,7 +907,7 @@ auto OpenGl20Renderer::createGlTexture(ImageView const& image, TextureAddressing
|
|||||||
|
|
||||||
glGenTextures(1, &glLoneTexture->textureId);
|
glGenTextures(1, &glLoneTexture->textureId);
|
||||||
if (glLoneTexture->textureId == 0)
|
if (glLoneTexture->textureId == 0)
|
||||||
throw RendererException("Could not generate texture in OpenGL20Renderer::createGlTexture");
|
throw RendererException("Could not generate texture in OpenGlRenderer::createGlTexture");
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, glLoneTexture->textureId);
|
glBindTexture(GL_TEXTURE_2D, glLoneTexture->textureId);
|
||||||
|
|
||||||
@ -872,14 +934,14 @@ auto OpenGl20Renderer::createGlTexture(ImageView const& image, TextureAddressing
|
|||||||
return glLoneTexture;
|
return glLoneTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto OpenGl20Renderer::createGlRenderBuffer() -> shared_ptr<GlRenderBuffer> {
|
auto OpenGlRenderer::createGlRenderBuffer() -> shared_ptr<GlRenderBuffer> {
|
||||||
auto glrb = make_shared<GlRenderBuffer>();
|
auto glrb = make_shared<GlRenderBuffer>();
|
||||||
glrb->whiteTexture = m_whiteTexture;
|
glrb->whiteTexture = m_whiteTexture;
|
||||||
glrb->useMultiTexturing = m_useMultiTexturing;
|
glrb->useMultiTexturing = m_useMultiTexturing;
|
||||||
return glrb;
|
return glrb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::renderGlBuffer(GlRenderBuffer const& renderBuffer, Mat3F const& transformation) {
|
void OpenGlRenderer::renderGlBuffer(GlRenderBuffer const& renderBuffer, Mat3F const& transformation) {
|
||||||
for (auto const& vb : renderBuffer.vertexBuffers) {
|
for (auto const& vb : renderBuffer.vertexBuffers) {
|
||||||
glUniformMatrix3fv(m_vertexTransformUniform, 1, GL_TRUE, transformation.ptr());
|
glUniformMatrix3fv(m_vertexTransformUniform, 1, GL_TRUE, transformation.ptr());
|
||||||
|
|
||||||
@ -900,30 +962,24 @@ void OpenGl20Renderer::renderGlBuffer(GlRenderBuffer const& renderBuffer, Mat3F
|
|||||||
|
|
||||||
glEnableVertexAttribArray(m_positionAttribute);
|
glEnableVertexAttribArray(m_positionAttribute);
|
||||||
glEnableVertexAttribArray(m_texCoordAttribute);
|
glEnableVertexAttribArray(m_texCoordAttribute);
|
||||||
glEnableVertexAttribArray(m_texIndexAttribute);
|
|
||||||
glEnableVertexAttribArray(m_colorAttribute);
|
glEnableVertexAttribArray(m_colorAttribute);
|
||||||
|
glEnableVertexAttribArray(m_dataAttribute);
|
||||||
|
|
||||||
glVertexAttribPointer(m_positionAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(GlRenderVertex), (GLvoid*)offsetof(GlRenderVertex, screenCoordinate));
|
glVertexAttribPointer(m_positionAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(GlRenderVertex), (GLvoid*)offsetof(GlRenderVertex, pos));
|
||||||
glVertexAttribPointer(m_texCoordAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(GlRenderVertex), (GLvoid*)offsetof(GlRenderVertex, textureCoordinate));
|
glVertexAttribPointer(m_texCoordAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(GlRenderVertex), (GLvoid*)offsetof(GlRenderVertex, uv));
|
||||||
glVertexAttribPointer(m_texIndexAttribute, 1, GL_FLOAT, GL_FALSE, sizeof(GlRenderVertex), (GLvoid*)offsetof(GlRenderVertex, textureIndex));
|
|
||||||
glVertexAttribPointer(m_colorAttribute, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GlRenderVertex), (GLvoid*)offsetof(GlRenderVertex, color));
|
glVertexAttribPointer(m_colorAttribute, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GlRenderVertex), (GLvoid*)offsetof(GlRenderVertex, color));
|
||||||
|
glVertexAttribIPointer(m_dataAttribute, 1, GL_INT, sizeof(GlRenderVertex), (GLvoid*)offsetof(GlRenderVertex, pack));
|
||||||
if (m_param1Attribute != -1) {
|
|
||||||
glEnableVertexAttribArray(m_param1Attribute);
|
|
||||||
glVertexAttribPointer(m_param1Attribute, 1, GL_FLOAT, GL_FALSE, sizeof(GlRenderVertex), (GLvoid*)offsetof(GlRenderVertex, param1));
|
|
||||||
}
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, vb.vertexCount);
|
glDrawArrays(GL_TRIANGLES, 0, vb.vertexCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Assumes the passed effect program is currently in use.
|
//Assumes the passed effect program is currently in use.
|
||||||
void OpenGl20Renderer::setupGlUniforms(Effect& effect) {
|
void OpenGlRenderer::setupGlUniforms(Effect& effect) {
|
||||||
m_positionAttribute = effect.getAttribute("vertexPosition");
|
m_positionAttribute = effect.getAttribute("vertexPosition");
|
||||||
m_texCoordAttribute = effect.getAttribute("vertexTextureCoordinate");
|
|
||||||
m_texIndexAttribute = effect.getAttribute("vertexTextureIndex");
|
|
||||||
m_colorAttribute = effect.getAttribute("vertexColor");
|
m_colorAttribute = effect.getAttribute("vertexColor");
|
||||||
m_param1Attribute = effect.getAttribute("vertexParam1");
|
m_texCoordAttribute = effect.getAttribute("vertexTextureCoordinate");
|
||||||
|
m_dataAttribute = effect.getAttribute("vertexData");
|
||||||
|
|
||||||
m_textureUniforms.clear();
|
m_textureUniforms.clear();
|
||||||
m_textureSizeUniforms.clear();
|
m_textureSizeUniforms.clear();
|
||||||
@ -940,14 +996,14 @@ void OpenGl20Renderer::setupGlUniforms(Effect& effect) {
|
|||||||
glUniform2f(m_screenSizeUniform, m_screenSize[0], m_screenSize[1]);
|
glUniform2f(m_screenSizeUniform, m_screenSize[0], m_screenSize[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<OpenGl20Renderer::GlFrameBuffer> OpenGl20Renderer::getGlFrameBuffer(String const& id) {
|
RefPtr<OpenGlRenderer::GlFrameBuffer> OpenGlRenderer::getGlFrameBuffer(String const& id) {
|
||||||
if (auto ptr = m_frameBuffers.ptr(id))
|
if (auto ptr = m_frameBuffers.ptr(id))
|
||||||
return *ptr;
|
return *ptr;
|
||||||
else
|
else
|
||||||
throw RendererException::format("Frame buffer '{}' does not exist", id);
|
throw RendererException::format("Frame buffer '{}' does not exist", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::blitGlFrameBuffer(RefPtr<GlFrameBuffer> const& frameBuffer) {
|
void OpenGlRenderer::blitGlFrameBuffer(RefPtr<GlFrameBuffer> const& frameBuffer) {
|
||||||
if (frameBuffer->blitted)
|
if (frameBuffer->blitted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -963,7 +1019,7 @@ void OpenGl20Renderer::blitGlFrameBuffer(RefPtr<GlFrameBuffer> const& frameBuffe
|
|||||||
frameBuffer->blitted = true;
|
frameBuffer->blitted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::switchGlFrameBuffer(RefPtr<GlFrameBuffer> const& frameBuffer) {
|
void OpenGlRenderer::switchGlFrameBuffer(RefPtr<GlFrameBuffer> const& frameBuffer) {
|
||||||
if (m_currentFrameBuffer == frameBuffer)
|
if (m_currentFrameBuffer == frameBuffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -971,7 +1027,7 @@ void OpenGl20Renderer::switchGlFrameBuffer(RefPtr<GlFrameBuffer> const& frameBuf
|
|||||||
m_currentFrameBuffer = frameBuffer;
|
m_currentFrameBuffer = frameBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint OpenGl20Renderer::Effect::getAttribute(String const& name) {
|
GLuint OpenGlRenderer::Effect::getAttribute(String const& name) {
|
||||||
auto find = attributes.find(name);
|
auto find = attributes.find(name);
|
||||||
if (find == attributes.end()) {
|
if (find == attributes.end()) {
|
||||||
GLuint attrib = glGetAttribLocation(program, name.utf8Ptr());
|
GLuint attrib = glGetAttribLocation(program, name.utf8Ptr());
|
||||||
@ -981,7 +1037,7 @@ GLuint OpenGl20Renderer::Effect::getAttribute(String const& name) {
|
|||||||
return find->second;
|
return find->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint OpenGl20Renderer::Effect::getUniform(String const& name) {
|
GLuint OpenGlRenderer::Effect::getUniform(String const& name) {
|
||||||
auto find = uniforms.find(name);
|
auto find = uniforms.find(name);
|
||||||
if (find == uniforms.end()) {
|
if (find == uniforms.end()) {
|
||||||
GLuint uniform = glGetUniformLocation(program, name.utf8Ptr());
|
GLuint uniform = glGetUniformLocation(program, name.utf8Ptr());
|
@ -7,16 +7,16 @@
|
|||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
STAR_CLASS(OpenGl20Renderer);
|
STAR_CLASS(OpenGlRenderer);
|
||||||
|
|
||||||
constexpr size_t FrameBufferCount = 1;
|
constexpr size_t FrameBufferCount = 1;
|
||||||
|
|
||||||
// OpenGL 2.0 implementation of Renderer. OpenGL context must be created and
|
// OpenGL 2.0 implementation of Renderer. OpenGL context must be created and
|
||||||
// active during construction, destruction, and all method calls.
|
// active during construction, destruction, and all method calls.
|
||||||
class OpenGl20Renderer : public Renderer {
|
class OpenGlRenderer : public Renderer {
|
||||||
public:
|
public:
|
||||||
OpenGl20Renderer();
|
OpenGlRenderer();
|
||||||
~OpenGl20Renderer();
|
~OpenGlRenderer();
|
||||||
|
|
||||||
String rendererId() const override;
|
String rendererId() const override;
|
||||||
Vec2U screenSize() const override;
|
Vec2U screenSize() const override;
|
||||||
@ -34,6 +34,7 @@ public:
|
|||||||
TexturePtr createTexture(Image const& texture, TextureAddressing addressing, TextureFiltering filtering) override;
|
TexturePtr createTexture(Image const& texture, TextureAddressing addressing, TextureFiltering filtering) override;
|
||||||
void setSizeLimitEnabled(bool enabled) override;
|
void setSizeLimitEnabled(bool enabled) override;
|
||||||
void setMultiTexturingEnabled(bool enabled) override;
|
void setMultiTexturingEnabled(bool enabled) override;
|
||||||
|
void setMultiSampling(unsigned multiSampling) override;
|
||||||
TextureGroupPtr createTextureGroup(TextureGroupSize size, TextureFiltering filtering) override;
|
TextureGroupPtr createTextureGroup(TextureGroupSize size, TextureFiltering filtering) override;
|
||||||
RenderBufferPtr createRenderBuffer() override;
|
RenderBufferPtr createRenderBuffer() override;
|
||||||
|
|
||||||
@ -112,12 +113,22 @@ private:
|
|||||||
TextureFiltering textureFiltering = TextureFiltering::Nearest;
|
TextureFiltering textureFiltering = TextureFiltering::Nearest;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GlPackedVertexData {
|
||||||
|
uint32_t textureIndex : 2;
|
||||||
|
uint32_t fullbright : 1;
|
||||||
|
uint32_t rX : 1;
|
||||||
|
uint32_t rY : 1;
|
||||||
|
uint32_t unused : 27;
|
||||||
|
};
|
||||||
|
|
||||||
struct GlRenderVertex {
|
struct GlRenderVertex {
|
||||||
Vec2F screenCoordinate;
|
Vec2F pos;
|
||||||
Vec2F textureCoordinate;
|
Vec2F uv;
|
||||||
float textureIndex;
|
|
||||||
Vec4B color;
|
Vec4B color;
|
||||||
float param1;
|
union Packed {
|
||||||
|
uint32_t packed;
|
||||||
|
GlPackedVertexData vars;
|
||||||
|
} pack;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GlRenderBuffer : public RenderBuffer {
|
struct GlRenderBuffer : public RenderBuffer {
|
||||||
@ -166,6 +177,7 @@ private:
|
|||||||
|
|
||||||
Json config;
|
Json config;
|
||||||
bool blitted = false;
|
bool blitted = false;
|
||||||
|
unsigned multisample = 0;
|
||||||
|
|
||||||
GlFrameBuffer(Json const& config);
|
GlFrameBuffer(Json const& config);
|
||||||
~GlFrameBuffer();
|
~GlFrameBuffer();
|
||||||
@ -199,25 +211,25 @@ private:
|
|||||||
|
|
||||||
void setupGlUniforms(Effect& effect);
|
void setupGlUniforms(Effect& effect);
|
||||||
|
|
||||||
RefPtr<OpenGl20Renderer::GlFrameBuffer> getGlFrameBuffer(String const& id);
|
RefPtr<OpenGlRenderer::GlFrameBuffer> getGlFrameBuffer(String const& id);
|
||||||
void blitGlFrameBuffer(RefPtr<OpenGl20Renderer::GlFrameBuffer> const& frameBuffer);
|
void blitGlFrameBuffer(RefPtr<OpenGlRenderer::GlFrameBuffer> const& frameBuffer);
|
||||||
void switchGlFrameBuffer(RefPtr<OpenGl20Renderer::GlFrameBuffer> const& frameBuffer);
|
void switchGlFrameBuffer(RefPtr<OpenGlRenderer::GlFrameBuffer> const& frameBuffer);
|
||||||
|
|
||||||
Vec2U m_screenSize;
|
Vec2U m_screenSize;
|
||||||
|
|
||||||
GLuint m_program = 0;
|
GLuint m_program = 0;
|
||||||
|
|
||||||
GLint m_positionAttribute = -1;
|
GLint m_positionAttribute = -1;
|
||||||
GLint m_texCoordAttribute = -1;
|
|
||||||
GLint m_texIndexAttribute = -1;
|
|
||||||
GLint m_colorAttribute = -1;
|
GLint m_colorAttribute = -1;
|
||||||
GLint m_param1Attribute = -1;
|
GLint m_texCoordAttribute = -1;
|
||||||
|
GLint m_dataAttribute = -1;
|
||||||
List<GLint> m_textureUniforms = {};
|
List<GLint> m_textureUniforms = {};
|
||||||
List<GLint> m_textureSizeUniforms = {};
|
List<GLint> m_textureSizeUniforms = {};
|
||||||
GLint m_screenSizeUniform = -1;
|
GLint m_screenSizeUniform = -1;
|
||||||
GLint m_vertexTransformUniform = -1;
|
GLint m_vertexTransformUniform = -1;
|
||||||
|
|
||||||
|
Json m_config;
|
||||||
|
|
||||||
StringMap<Effect> m_effects;
|
StringMap<Effect> m_effects;
|
||||||
Effect* m_currentEffect;
|
Effect* m_currentEffect;
|
||||||
|
|
||||||
@ -230,6 +242,7 @@ private:
|
|||||||
|
|
||||||
bool m_limitTextureGroupSize;
|
bool m_limitTextureGroupSize;
|
||||||
bool m_useMultiTexturing;
|
bool m_useMultiTexturing;
|
||||||
|
unsigned m_multiSampling; // if non-zero, is enabled and acts as sample count
|
||||||
List<shared_ptr<GlTextureGroup>> m_liveTextureGroups;
|
List<shared_ptr<GlTextureGroup>> m_liveTextureGroups;
|
||||||
|
|
||||||
List<RenderPrimitive> m_immediatePrimitives;
|
List<RenderPrimitive> m_immediatePrimitives;
|
@ -870,6 +870,42 @@ ImageConstPtr Assets::readImage(String const& path) const {
|
|||||||
image = memorySource->image(p->sourceName);
|
image = memorySource->image(p->sourceName);
|
||||||
if (!image)
|
if (!image)
|
||||||
image = make_shared<Image>(Image::readPng(p->source->open(p->sourceName)));
|
image = make_shared<Image>(Image::readPng(p->source->open(p->sourceName)));
|
||||||
|
|
||||||
|
if (!p->patchSources.empty()) {
|
||||||
|
MutexLocker luaLocker(m_luaMutex);
|
||||||
|
LuaEngine* luaEngine = as<LuaEngine>(m_luaEngine.get());
|
||||||
|
LuaValue result = luaEngine->createUserData(*image);
|
||||||
|
luaLocker.unlock();
|
||||||
|
for (auto const& pair : p->patchSources) {
|
||||||
|
auto& patchPath = pair.first;
|
||||||
|
auto& patchSource = pair.second;
|
||||||
|
auto patchStream = patchSource->read(patchPath);
|
||||||
|
if (patchPath.endsWith(".lua")) {
|
||||||
|
luaLocker.lock();
|
||||||
|
LuaContextPtr& context = m_patchContexts[patchPath];
|
||||||
|
if (!context) {
|
||||||
|
context = make_shared<LuaContext>(luaEngine->createContext());
|
||||||
|
context->load(patchStream, patchPath);
|
||||||
|
}
|
||||||
|
auto newResult = context->invokePath<LuaValue>("patch", result, path);
|
||||||
|
if (!newResult.is<LuaNilType>()) {
|
||||||
|
if (auto ud = newResult.ptr<LuaUserData>()) {
|
||||||
|
if (ud->is<Image>())
|
||||||
|
result = std::move(newResult);
|
||||||
|
else
|
||||||
|
Logger::warn("Patch '{}' for image '{}' returned a non-Image userdata value, ignoring");
|
||||||
|
} else {
|
||||||
|
Logger::warn("Patch '{}' for image '{}' returned a non-Image value, ignoring");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
luaLocker.unlock();
|
||||||
|
} else {
|
||||||
|
Logger::warn("Patch '{}' for image '{}' isn't a Lua script, ignoring", patchPath, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
image = make_shared<Image>(std::move(result.get<LuaUserData>().get<Image>()));
|
||||||
|
}
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
throw AssetException(strf("No such asset '{}'", path));
|
throw AssetException(strf("No such asset '{}'", path));
|
||||||
@ -916,32 +952,32 @@ Json Assets::readJson(String const& path) const {
|
|||||||
auto& patchPath = pair.first;
|
auto& patchPath = pair.first;
|
||||||
auto& patchSource = pair.second;
|
auto& patchSource = pair.second;
|
||||||
auto patchStream = patchSource->read(patchPath);
|
auto patchStream = patchSource->read(patchPath);
|
||||||
if (pair.first.endsWith(".lua")) {
|
if (patchPath.endsWith(".lua")) {
|
||||||
MutexLocker luaLocker(m_luaMutex);
|
MutexLocker luaLocker(m_luaMutex);
|
||||||
// Kae: i don't like that lock. perhaps have a LuaEngine and patch context cache per worker thread later on?
|
// Kae: i don't like that lock. perhaps have a LuaEngine and patch context cache per worker thread later on?
|
||||||
LuaContextPtr& context = m_patchContexts[patchPath];
|
LuaContextPtr& context = m_patchContexts[patchPath];
|
||||||
if (!context) {
|
if (!context) {
|
||||||
context = make_shared<LuaContext>(as<LuaEngine>(m_luaEngine.get())->createContext());
|
context = make_shared<LuaContext>(as<LuaEngine>(m_luaEngine.get())->createContext());
|
||||||
context->load(patchStream, patchPath);
|
context->load(patchStream, patchPath);
|
||||||
}
|
|
||||||
auto newResult = context->invokePath<Json>("patch", result, path);
|
|
||||||
if (newResult)
|
|
||||||
result = std::move(newResult);
|
|
||||||
} else {
|
|
||||||
auto patchJson = inputUtf8Json(patchStream.begin(), patchStream.end(), false);
|
|
||||||
if (patchJson.isType(Json::Type::Array)) {
|
|
||||||
auto patchData = patchJson.toArray();
|
|
||||||
try {
|
|
||||||
result = checkPatchArray(patchPath, patchSource, result, patchData, {});
|
|
||||||
} catch (JsonPatchTestFail const& e) {
|
|
||||||
Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what());
|
|
||||||
} catch (JsonPatchException const& e) {
|
|
||||||
Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what());
|
|
||||||
}
|
|
||||||
} else if (patchJson.isType(Json::Type::Object)) {//Kae: Do a good ol' json merge instead if the .patch file is a Json object
|
|
||||||
result = jsonMergeNulling(result, patchJson.toObject());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
auto newResult = context->invokePath<Json>("patch", result, path);
|
||||||
|
if (newResult)
|
||||||
|
result = std::move(newResult);
|
||||||
|
} else {
|
||||||
|
auto patchJson = inputUtf8Json(patchStream.begin(), patchStream.end(), false);
|
||||||
|
if (patchJson.isType(Json::Type::Array)) {
|
||||||
|
auto patchData = patchJson.toArray();
|
||||||
|
try {
|
||||||
|
result = checkPatchArray(patchPath, patchSource, result, patchData, {});
|
||||||
|
} catch (JsonPatchTestFail const& e) {
|
||||||
|
Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what());
|
||||||
|
} catch (JsonPatchException const& e) {
|
||||||
|
Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what());
|
||||||
|
}
|
||||||
|
} else if (patchJson.isType(Json::Type::Object)) {//Kae: Do a good ol' json merge instead if the .patch file is a Json object
|
||||||
|
result = jsonMergeNulling(result, patchJson.toObject());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} catch (std::exception const& e) {
|
} catch (std::exception const& e) {
|
||||||
|
@ -58,6 +58,7 @@ Json const AdditionalDefaultConfiguration = Json::parseJson(R"JSON(
|
|||||||
"fullscreen" : false,
|
"fullscreen" : false,
|
||||||
"borderless" : false,
|
"borderless" : false,
|
||||||
"maximized" : true,
|
"maximized" : true,
|
||||||
|
"antiAliasing" : false,
|
||||||
"zoomLevel" : 3.0,
|
"zoomLevel" : 3.0,
|
||||||
"cameraSpeedFactor" : 1.0,
|
"cameraSpeedFactor" : 1.0,
|
||||||
"speechBubbles" : true,
|
"speechBubbles" : true,
|
||||||
@ -375,6 +376,7 @@ void ClientApplication::render() {
|
|||||||
auto assets = m_root->assets();
|
auto assets = m_root->assets();
|
||||||
auto& renderer = Application::renderer();
|
auto& renderer = Application::renderer();
|
||||||
|
|
||||||
|
renderer->setMultiSampling(config->get("antiAliasing").optBool().value(false) ? 4 : 0);
|
||||||
renderer->switchEffectConfig("interface");
|
renderer->switchEffectConfig("interface");
|
||||||
|
|
||||||
if (m_guiContext->windowWidth() >= m_crossoverRes[0] && m_guiContext->windowHeight() >= m_crossoverRes[1])
|
if (m_guiContext->windowWidth() >= m_crossoverRes[0] && m_guiContext->windowHeight() >= m_crossoverRes[1])
|
||||||
@ -452,7 +454,7 @@ void ClientApplication::renderReload() {
|
|||||||
Logger::warn("No rendering config found for renderer with id '{}'", renderer->rendererId());
|
Logger::warn("No rendering config found for renderer with id '{}'", renderer->rendererId());
|
||||||
};
|
};
|
||||||
|
|
||||||
renderer->loadConfig(assets->json("/rendering/opengl20.config"));
|
renderer->loadConfig(assets->json("/rendering/opengl.config"));
|
||||||
|
|
||||||
loadEffectConfig("world");
|
loadEffectConfig("world");
|
||||||
loadEffectConfig("interface");
|
loadEffectConfig("interface");
|
||||||
|
@ -74,6 +74,12 @@ GraphicsMenu::GraphicsMenu() {
|
|||||||
m_localChanges.set("useMultiTexturing", fetchChild<ButtonWidget>("multiTextureCheckbox")->isChecked());
|
m_localChanges.set("useMultiTexturing", fetchChild<ButtonWidget>("multiTextureCheckbox")->isChecked());
|
||||||
syncGui();
|
syncGui();
|
||||||
});
|
});
|
||||||
|
reader.registerCallback("antiAliasingCheckbox", [=](Widget*) {
|
||||||
|
bool checked = fetchChild<ButtonWidget>("antiAliasingCheckbox")->isChecked();
|
||||||
|
m_localChanges.set("antiAliasing", checked);
|
||||||
|
Root::singleton().configuration()->set("antiAliasing", checked);
|
||||||
|
syncGui();
|
||||||
|
});
|
||||||
reader.registerCallback("monochromeCheckbox", [=](Widget*) {
|
reader.registerCallback("monochromeCheckbox", [=](Widget*) {
|
||||||
bool checked = fetchChild<ButtonWidget>("monochromeCheckbox")->isChecked();
|
bool checked = fetchChild<ButtonWidget>("monochromeCheckbox")->isChecked();
|
||||||
m_localChanges.set("monochromeLighting", checked);
|
m_localChanges.set("monochromeLighting", checked);
|
||||||
@ -133,6 +139,7 @@ StringList const GraphicsMenu::ConfigKeys = {
|
|||||||
"borderless",
|
"borderless",
|
||||||
"limitTextureAtlasSize",
|
"limitTextureAtlasSize",
|
||||||
"useMultiTexturing",
|
"useMultiTexturing",
|
||||||
|
"antiAliasing",
|
||||||
"monochromeLighting"
|
"monochromeLighting"
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -187,6 +194,7 @@ void GraphicsMenu::syncGui() {
|
|||||||
fetchChild<ButtonWidget>("borderlessCheckbox")->setChecked(m_localChanges.get("borderless").toBool());
|
fetchChild<ButtonWidget>("borderlessCheckbox")->setChecked(m_localChanges.get("borderless").toBool());
|
||||||
fetchChild<ButtonWidget>("textureLimitCheckbox")->setChecked(m_localChanges.get("limitTextureAtlasSize").toBool());
|
fetchChild<ButtonWidget>("textureLimitCheckbox")->setChecked(m_localChanges.get("limitTextureAtlasSize").toBool());
|
||||||
fetchChild<ButtonWidget>("multiTextureCheckbox")->setChecked(m_localChanges.get("useMultiTexturing").optBool().value(true));
|
fetchChild<ButtonWidget>("multiTextureCheckbox")->setChecked(m_localChanges.get("useMultiTexturing").optBool().value(true));
|
||||||
|
fetchChild<ButtonWidget>("antiAliasingCheckbox")->setChecked(m_localChanges.get("antiAliasing").toBool());
|
||||||
fetchChild<ButtonWidget>("monochromeCheckbox")->setChecked(m_localChanges.get("monochromeLighting").toBool());
|
fetchChild<ButtonWidget>("monochromeCheckbox")->setChecked(m_localChanges.get("monochromeLighting").toBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
void WorldCamera::setCenterWorldPosition(Vec2F const& position) {
|
void WorldCamera::setCenterWorldPosition(Vec2F const& position, bool force) {
|
||||||
// Only actually move the world center if a half pixel distance has been
|
// Only actually move the world center if a half pixel distance has been
|
||||||
// moved in any direction. This is sort of arbitrary, but helps prevent
|
// moved in any direction. This is sort of arbitrary, but helps prevent
|
||||||
// judder if the camera is at a boundary and floating point inaccuracy is
|
// judder if the camera is at a boundary and floating point inaccuracy is
|
||||||
// causing the focus to jitter back and forth across the boundary.
|
// causing the focus to jitter back and forth across the boundary.
|
||||||
if (fabs(position[0] - m_worldCenter[0]) < 1.0f / (TilePixels * m_pixelRatio * 2) && fabs(position[1] - m_worldCenter[1]) < 1.0f / (TilePixels * m_pixelRatio * 2))
|
if (fabs(position[0] - m_worldCenter[0]) < 1.0f / (TilePixels * m_pixelRatio * 2)
|
||||||
|
&& fabs(position[1] - m_worldCenter[1]) < 1.0f / (TilePixels * m_pixelRatio * 2) && !force)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// First, make sure the camera center position is inside the main x
|
// First, make sure the camera center position is inside the main x
|
||||||
|
@ -20,8 +20,8 @@ public:
|
|||||||
|
|
||||||
// Set the camera center position (in world space) to as close to the given
|
// Set the camera center position (in world space) to as close to the given
|
||||||
// location as possible while keeping the screen within world bounds.
|
// location as possible while keeping the screen within world bounds.
|
||||||
|
void setCenterWorldPosition(Vec2F const& position, bool force = false);
|
||||||
// Returns the actual camera position.
|
// Returns the actual camera position.
|
||||||
void setCenterWorldPosition(Vec2F const& position);
|
|
||||||
Vec2F centerWorldPosition() const;
|
Vec2F centerWorldPosition() const;
|
||||||
|
|
||||||
// Transforms world coordinates into one set of screen coordinates. Since
|
// Transforms world coordinates into one set of screen coordinates. Since
|
||||||
@ -121,7 +121,11 @@ inline Vec2F WorldCamera::tileMinScreen() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void WorldCamera::update(float dt) {
|
inline void WorldCamera::update(float dt) {
|
||||||
m_pixelRatio = lerp(exp(-20.0f * dt), m_targetPixelRatio, m_pixelRatio);
|
float newPixelRatio = lerp(exp(-20.0f * dt), m_targetPixelRatio, m_pixelRatio);
|
||||||
|
if (m_pixelRatio != newPixelRatio) {
|
||||||
|
m_pixelRatio = newPixelRatio;
|
||||||
|
setCenterWorldPosition(m_worldCenter, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user