mirror of
https://github.com/izzy2lost/Super3.git
synced 2026-07-05 15:18:38 -07:00
Added experimental real3d option
This commit is contained in:
@@ -13,21 +13,24 @@ This app does **not** include any games, ROMs, BIOS files, or copyrighted game c
|
||||
- In-game pause/resume button.
|
||||
|
||||
## Video settings (Resolution & Widescreen)
|
||||
From the main game list, open the side menu (toolbar “menu” icon) and look under **Video**.
|
||||
From the main game list, open the side menu (toolbar "menu" icon) and look under **Video**.
|
||||
|
||||
- **Resolution:** Native (496×384) and integer scale options (2× through 8×). Higher values look sharper but can reduce performance.
|
||||
- **Match device resolution:** Sets the internal resolution to your device’s exact pixel resolution (landscape). This also enables **Widescreen** and **Wide background**.
|
||||
- **Resolution:** Native (496x384) and integer scale options (2x through 8x). Higher values look sharper but can reduce performance.
|
||||
- **Match device resolution:** Sets the internal resolution to your device's exact pixel resolution (landscape). This also enables **Widescreen** and **Wide background**.
|
||||
- **Widescreen:** Expands the horizontal field of view (Supermodel `-wide-screen`). At very wide aspect ratios some games may cull objects at the edges.
|
||||
- **Wide background:** Stretches the 2D background layers when using widescreen (Supermodel `-wide-bg`).
|
||||
- **Enhanced Real3D (experimental):** Enables more desktop-like Real3D rendering (multi-pass transparency compositing + scroll fog). This can improve visuals in some games/areas, but may reduce performance on lower-end devices.
|
||||
|
||||
These settings are written to `.../Android/data/<package>/files/super3/Config/Supermodel.ini` (`XResolution`, `YResolution`, `WideScreen`, `WideBackground`, `New3DAccurate`).
|
||||
|
||||
## Files & Storage
|
||||
- Save states and thumbnails are stored under the app’s user data directory in `Saves/` (for example: `.../Android/data/<package>/files/super3/Saves/`).
|
||||
- The app may offer an optional “sync”/export workflow using Android’s Storage Access Framework. If enabled, the app only accesses the folder(s) you explicitly choose.
|
||||
- Save states and thumbnails are stored under the app's user data directory in `Saves/` (for example: `.../Android/data/<package>/files/super3/Saves/`).
|
||||
- The app may offer an optional "sync"/export workflow using Android's Storage Access Framework. If enabled, the app only accesses the folder(s) you explicitly choose.
|
||||
|
||||
## Legal / Google Play Policy Notes
|
||||
- **No games included:** SUPER3 does not ship with ROMs or game data, and it is not intended to facilitate piracy.
|
||||
- **You must own the games:** Only use ROMs you are legally permitted to use in your region.
|
||||
- **Trademarks:** “SEGA” and all associated game names, trademarks, and copyrighted works are the property of their respective owners.
|
||||
- **Trademarks:** "SEGA" and all associated game names, trademarks, and copyrighted works are the property of their respective owners.
|
||||
- **Not affiliated:** This project is not affiliated with or endorsed by SEGA or any arcade hardware manufacturer.
|
||||
|
||||
## Privacy
|
||||
|
||||
@@ -17,10 +17,8 @@
|
||||
namespace New3D {
|
||||
|
||||
CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName)
|
||||
: m_r3dShader(config),
|
||||
#ifndef __ANDROID__
|
||||
m_r3dScrollFog(config),
|
||||
#endif
|
||||
: m_config(config),
|
||||
m_r3dShader(config),
|
||||
m_gameName(gameName)
|
||||
{
|
||||
m_cullingRAMLo = nullptr;
|
||||
@@ -30,6 +28,7 @@ CNew3D::CNew3D(const Util::Config::Node &config, const std::string& gameName)
|
||||
m_textureRAM = nullptr;
|
||||
m_sunClamp = true;
|
||||
m_shadeIsSigned = true;
|
||||
m_new3dAccurate = config["New3DAccurate"].ValueAsDefault<bool>(false);
|
||||
m_numPolyVerts = 3;
|
||||
m_primType = GL_TRIANGLES;
|
||||
|
||||
@@ -89,7 +88,23 @@ bool CNew3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yR
|
||||
|
||||
m_r3dShader.LoadShader();
|
||||
#ifndef __ANDROID__
|
||||
m_r3dFrameBuffers.CreateFBO(totalXResParam, totalYResParam);
|
||||
if (!m_r3dFrameBuffers)
|
||||
m_r3dFrameBuffers = std::make_unique<R3DFrameBuffers>();
|
||||
if (!m_r3dScrollFog)
|
||||
m_r3dScrollFog = std::make_unique<R3DScrollFog>(m_config);
|
||||
m_r3dFrameBuffers->CreateFBO((int)totalXResParam, (int)totalYResParam);
|
||||
#else
|
||||
if (m_new3dAccurate) {
|
||||
if (!m_r3dFrameBuffers)
|
||||
m_r3dFrameBuffers = std::make_unique<R3DFrameBuffers>();
|
||||
if (!m_r3dScrollFog)
|
||||
m_r3dScrollFog = std::make_unique<R3DScrollFog>(m_config);
|
||||
if (!m_r3dFrameBuffers->CreateFBO((int)totalXResParam, (int)totalYResParam)) {
|
||||
m_r3dFrameBuffers.reset();
|
||||
m_r3dScrollFog.reset();
|
||||
m_new3dAccurate = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
glUseProgram(0);
|
||||
@@ -122,7 +137,11 @@ void CNew3D::UploadTextures(unsigned level, unsigned x, unsigned y, unsigned wid
|
||||
|
||||
void CNew3D::DrawScrollFog()
|
||||
{
|
||||
#ifndef __ANDROID__
|
||||
#ifdef __ANDROID__
|
||||
if (!m_new3dAccurate) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// this is my best guess at the logic based upon what games are doing
|
||||
//
|
||||
// ocean hunter - every viewport has scroll fog values set. Must start with lowest priority layers as the higher ones sometimes are garbage
|
||||
@@ -164,7 +183,9 @@ CheckScroll:
|
||||
rgba[2] == n.viewport.fogParams[2]) {
|
||||
|
||||
glViewport(n.viewport.x, n.viewport.y, n.viewport.width, n.viewport.height);
|
||||
m_r3dScrollFog.DrawScrollFog(rgba, n.viewport.scrollAtt, n.viewport.fogParams[6], n.viewport.spotFogColor, n.viewport.spotEllipse);
|
||||
if (m_r3dScrollFog) {
|
||||
m_r3dScrollFog->DrawScrollFog(rgba, n.viewport.scrollAtt, n.viewport.fogParams[6], n.viewport.spotFogColor, n.viewport.spotEllipse);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -172,7 +193,6 @@ CheckScroll:
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CNew3D::RenderScene(int priority, bool renderOverlay, Layer layer)
|
||||
@@ -314,7 +334,8 @@ void CNew3D::DisableRenderStates()
|
||||
void CNew3D::RenderFrame(void)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
// Android/GLES: basic mesh path (no multi-pass transparency compositing yet).
|
||||
if (!m_new3dAccurate) {
|
||||
// Android/GLES: basic mesh path (no multi-pass transparency compositing yet).
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m_nfPairs[i].zNear = -std::numeric_limits<float>::max();
|
||||
m_nfPairs[i].zFar = std::numeric_limits<float>::max();
|
||||
@@ -383,8 +404,9 @@ void CNew3D::RenderFrame(void)
|
||||
glDepthMask(GL_TRUE);
|
||||
DisableRenderStates();
|
||||
}
|
||||
return;
|
||||
#else
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m_nfPairs[i].zNear = -std::numeric_limits<float>::max();
|
||||
m_nfPairs[i].zFar = std::numeric_limits<float>::max();
|
||||
@@ -431,7 +453,8 @@ void CNew3D::RenderFrame(void)
|
||||
}
|
||||
}
|
||||
|
||||
m_r3dFrameBuffers.SetFBO(Layer::trans12);
|
||||
if (!m_r3dFrameBuffers) return;
|
||||
m_r3dFrameBuffers->SetFBO(Layer::trans12);
|
||||
glClear(GL_COLOR_BUFFER_BIT); // wipe both trans layers
|
||||
|
||||
for (int pri = 0; pri <= 3; pri++) {
|
||||
@@ -442,7 +465,7 @@ void CNew3D::RenderFrame(void)
|
||||
|
||||
bool renderOverlay = (i == 1);
|
||||
|
||||
m_r3dFrameBuffers.SetFBO(Layer::colour);
|
||||
m_r3dFrameBuffers->SetFBO(Layer::colour);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
SetRenderStates();
|
||||
@@ -456,20 +479,20 @@ void CNew3D::RenderFrame(void)
|
||||
|
||||
DisableRenderStates();
|
||||
|
||||
m_r3dFrameBuffers.DrawOverTransLayers(); // mask trans layer with opaque pixels
|
||||
m_r3dFrameBuffers.CompositeBaseLayer(); // copy opaque pixels to back buffer
|
||||
m_r3dFrameBuffers->DrawOverTransLayers(); // mask trans layer with opaque pixels
|
||||
m_r3dFrameBuffers->CompositeBaseLayer(); // copy opaque pixels to back buffer
|
||||
|
||||
SetRenderStates();
|
||||
|
||||
glDepthFunc(GL_LESS); // alpha polys seem to use gl_less (ocean hunter)
|
||||
|
||||
m_r3dShader.DiscardAlpha (false); // render only translucent pixels
|
||||
m_r3dFrameBuffers.StoreDepth (); // save depth buffer for 1st trans pass
|
||||
m_r3dFrameBuffers.SetFBO (Layer::trans1);
|
||||
m_r3dFrameBuffers->StoreDepth (); // save depth buffer for 1st trans pass
|
||||
m_r3dFrameBuffers->SetFBO (Layer::trans1);
|
||||
RenderScene (pri, renderOverlay, Layer::trans1);
|
||||
|
||||
m_r3dFrameBuffers.RestoreDepth (); // restore depth buffer, trans layers don't seem to depth test against each other
|
||||
m_r3dFrameBuffers.SetFBO (Layer::trans2);
|
||||
m_r3dFrameBuffers->RestoreDepth (); // restore depth buffer, trans layers don't seem to depth test against each other
|
||||
m_r3dFrameBuffers->SetFBO (Layer::trans2);
|
||||
RenderScene (pri, renderOverlay, Layer::trans2);
|
||||
|
||||
DisableRenderStates();
|
||||
@@ -478,8 +501,7 @@ void CNew3D::RenderFrame(void)
|
||||
}
|
||||
}
|
||||
|
||||
m_r3dFrameBuffers.CompositeAlphaLayer();
|
||||
#endif
|
||||
m_r3dFrameBuffers->CompositeAlphaLayer();
|
||||
}
|
||||
|
||||
void CNew3D::BeginFrame(void)
|
||||
|
||||
@@ -39,19 +39,17 @@
|
||||
#include "Graphics/IRender3D.h"
|
||||
#include "Model.h"
|
||||
#include "Mat4.h"
|
||||
#include "Util/NewConfig.h"
|
||||
#include "R3DShader.h"
|
||||
#include "VBO.h"
|
||||
#include "R3DData.h"
|
||||
#include "Plane.h"
|
||||
#include "Vec.h"
|
||||
#ifndef __ANDROID__
|
||||
#include "R3DScrollFog.h"
|
||||
#endif
|
||||
#include "PolyHeader.h"
|
||||
#ifndef __ANDROID__
|
||||
#include "R3DFrameBuffers.h"
|
||||
#endif
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
namespace New3D {
|
||||
|
||||
@@ -236,6 +234,7 @@ private:
|
||||
*/
|
||||
|
||||
// Misc
|
||||
const Util::Config::Node &m_config;
|
||||
std::string m_gameName;
|
||||
int m_numPolyVerts;
|
||||
GLenum m_primType;
|
||||
@@ -243,6 +242,7 @@ private:
|
||||
// GPU configuration
|
||||
bool m_sunClamp;
|
||||
bool m_shadeIsSigned;
|
||||
bool m_new3dAccurate;
|
||||
|
||||
// Stepping
|
||||
int m_step;
|
||||
@@ -290,10 +290,8 @@ private:
|
||||
|
||||
VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
|
||||
R3DShader m_r3dShader;
|
||||
#ifndef __ANDROID__
|
||||
R3DScrollFog m_r3dScrollFog;
|
||||
R3DFrameBuffers m_r3dFrameBuffers;
|
||||
#endif
|
||||
std::unique_ptr<R3DScrollFog> m_r3dScrollFog;
|
||||
std::unique_ptr<R3DFrameBuffers> m_r3dFrameBuffers;
|
||||
|
||||
Plane m_planes[5];
|
||||
|
||||
|
||||
@@ -189,7 +189,12 @@ void R3DFrameBuffers::SetFBO(Layer layer)
|
||||
case Layer::none:
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
#ifdef __ANDROID__
|
||||
GLenum buffers[] = { GL_BACK };
|
||||
glDrawBuffers(countof(buffers), buffers);
|
||||
#else
|
||||
glDrawBuffer(GL_BACK);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -199,6 +204,43 @@ void R3DFrameBuffers::SetFBO(Layer layer)
|
||||
|
||||
void R3DFrameBuffers::AllocShaderBase()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
const char *vertexShader = R"glsl(
|
||||
|
||||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
in vec3 inVertex;
|
||||
in vec2 inTexCoord;
|
||||
|
||||
out vec2 fsTexCoord;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
fsTexCoord = inTexCoord;
|
||||
gl_Position = vec4(inVertex,1.0);
|
||||
}
|
||||
|
||||
)glsl";
|
||||
|
||||
const char *fragmentShader = R"glsl(
|
||||
|
||||
#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D tex1;
|
||||
in vec2 fsTexCoord;
|
||||
out vec4 oColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 colBase = texture(tex1, fsTexCoord);
|
||||
if(colBase.a < 1.0) discard;
|
||||
oColor = colBase;
|
||||
}
|
||||
|
||||
)glsl";
|
||||
#else
|
||||
const char *vertexShader = R"glsl(
|
||||
|
||||
#version 120
|
||||
@@ -234,15 +276,62 @@ void R3DFrameBuffers::AllocShaderBase()
|
||||
}
|
||||
|
||||
)glsl";
|
||||
#endif
|
||||
|
||||
m_shaderBase.LoadShaders(vertexShader, fragmentShader);
|
||||
m_shaderBase.uniformLoc[0] = m_shaderTrans.GetUniformLocation("tex1");
|
||||
m_shaderBase.attribLoc[0] = m_shaderTrans.GetAttributeLocation("inVertex");
|
||||
m_shaderBase.attribLoc[1] = m_shaderTrans.GetAttributeLocation("inTexCoord");
|
||||
m_shaderBase.uniformLoc[0] = m_shaderBase.GetUniformLocation("tex1");
|
||||
m_shaderBase.attribLoc[0] = m_shaderBase.GetAttributeLocation("inVertex");
|
||||
m_shaderBase.attribLoc[1] = m_shaderBase.GetAttributeLocation("inTexCoord");
|
||||
}
|
||||
|
||||
void R3DFrameBuffers::AllocShaderTrans()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
const char *vertexShader = R"glsl(
|
||||
|
||||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
in vec3 inVertex;
|
||||
in vec2 inTexCoord;
|
||||
|
||||
out vec2 fsTexCoord;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
fsTexCoord = inTexCoord;
|
||||
gl_Position = vec4(inVertex,1.0);
|
||||
}
|
||||
|
||||
)glsl";
|
||||
|
||||
const char *fragmentShader = R"glsl(
|
||||
|
||||
#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D tex1;
|
||||
uniform sampler2D tex2;
|
||||
|
||||
in vec2 fsTexCoord;
|
||||
out vec4 oColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 colTrans1 = texture(tex1, fsTexCoord);
|
||||
vec4 colTrans2 = texture(tex2, fsTexCoord);
|
||||
|
||||
if(colTrans1.a + colTrans2.a > 0.0) {
|
||||
vec3 col1 = colTrans1.rgb * colTrans1.a;
|
||||
vec3 col2 = colTrans2.rgb * colTrans2.a;
|
||||
colTrans1 = vec4((col1 + col2) / (colTrans1.a + colTrans2.a), colTrans1.a + colTrans2.a);
|
||||
}
|
||||
|
||||
oColor = colTrans1;
|
||||
}
|
||||
|
||||
)glsl";
|
||||
#else
|
||||
const char *vertexShader = R"glsl(
|
||||
|
||||
#version 120
|
||||
@@ -288,6 +377,7 @@ void R3DFrameBuffers::AllocShaderTrans()
|
||||
}
|
||||
|
||||
)glsl";
|
||||
#endif
|
||||
|
||||
m_shaderTrans.LoadShaders(vertexShader, fragmentShader);
|
||||
|
||||
@@ -300,6 +390,48 @@ void R3DFrameBuffers::AllocShaderTrans()
|
||||
|
||||
void R3DFrameBuffers::AllocShaderWipe()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
const char *vertexShader = R"glsl(
|
||||
|
||||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
in vec3 inVertex;
|
||||
in vec2 inTexCoord;
|
||||
|
||||
out vec2 fsTexCoord;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
fsTexCoord = inTexCoord;
|
||||
gl_Position = vec4(inVertex,1.0);
|
||||
}
|
||||
|
||||
)glsl";
|
||||
|
||||
const char *fragmentShader = R"glsl(
|
||||
|
||||
#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D texColor;
|
||||
in vec2 fsTexCoord;
|
||||
|
||||
layout(location=0) out vec4 oLayer1;
|
||||
layout(location=1) out vec4 oLayer2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 colBase = texture(texColor, fsTexCoord);
|
||||
if(colBase.a == 0.0) {
|
||||
discard;
|
||||
}
|
||||
oLayer1 = vec4(0.0);
|
||||
oLayer2 = vec4(0.0);
|
||||
}
|
||||
|
||||
)glsl";
|
||||
#else
|
||||
const char *vertexShader = R"glsl(
|
||||
|
||||
#version 120
|
||||
@@ -339,13 +471,14 @@ void R3DFrameBuffers::AllocShaderWipe()
|
||||
}
|
||||
|
||||
)glsl";
|
||||
#endif
|
||||
|
||||
m_shaderWipe.LoadShaders(vertexShader, fragmentShader);
|
||||
|
||||
m_shaderWipe.uniformLoc[0] = m_shaderTrans.GetUniformLocation("texColor");
|
||||
m_shaderWipe.uniformLoc[0] = m_shaderWipe.GetUniformLocation("texColor");
|
||||
|
||||
m_shaderWipe.attribLoc[0] = m_shaderTrans.GetAttributeLocation("inVertex");
|
||||
m_shaderWipe.attribLoc[1] = m_shaderTrans.GetAttributeLocation("inTexCoord");
|
||||
m_shaderWipe.attribLoc[0] = m_shaderWipe.GetAttributeLocation("inVertex");
|
||||
m_shaderWipe.attribLoc[1] = m_shaderWipe.GetAttributeLocation("inTexCoord");
|
||||
}
|
||||
|
||||
void R3DFrameBuffers::Draw()
|
||||
@@ -437,16 +570,16 @@ void R3DFrameBuffers::DrawOverTransLayers()
|
||||
m_shaderWipe.EnableShader();
|
||||
glUniform1i(m_shaderWipe.uniformLoc[0], 0);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(m_shaderWipe.attribLoc[0]);
|
||||
glEnableVertexAttribArray(m_shaderWipe.attribLoc[1]);
|
||||
|
||||
glVertexAttribPointer(m_shaderWipe.attribLoc[0], 3, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, verts));
|
||||
glVertexAttribPointer(m_shaderWipe.attribLoc[1], 2, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, texCoords));
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(m_shaderWipe.attribLoc[0]);
|
||||
glDisableVertexAttribArray(m_shaderWipe.attribLoc[1]);
|
||||
|
||||
m_shaderWipe.DisableShader();
|
||||
|
||||
@@ -456,18 +589,18 @@ void R3DFrameBuffers::DrawOverTransLayers()
|
||||
void R3DFrameBuffers::DrawBaseLayer()
|
||||
{
|
||||
m_shaderBase.EnableShader();
|
||||
glUniform1i(m_shaderTrans.uniformLoc[0], 0);
|
||||
glUniform1i(m_shaderBase.uniformLoc[0], 0);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(m_shaderBase.attribLoc[0]);
|
||||
glEnableVertexAttribArray(m_shaderBase.attribLoc[1]);
|
||||
|
||||
glVertexAttribPointer(m_shaderTrans.attribLoc[0], 3, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, verts));
|
||||
glVertexAttribPointer(m_shaderTrans.attribLoc[1], 2, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, texCoords));
|
||||
glVertexAttribPointer(m_shaderBase.attribLoc[0], 3, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, verts));
|
||||
glVertexAttribPointer(m_shaderBase.attribLoc[1], 2, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, texCoords));
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(m_shaderBase.attribLoc[0]);
|
||||
glDisableVertexAttribArray(m_shaderBase.attribLoc[1]);
|
||||
|
||||
m_shaderBase.DisableShader();
|
||||
}
|
||||
@@ -478,16 +611,16 @@ void R3DFrameBuffers::DrawAlphaLayer()
|
||||
glUniform1i(m_shaderTrans.uniformLoc[0], 1); // tex unit 1
|
||||
glUniform1i(m_shaderTrans.uniformLoc[1], 2); // tex unit 2
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(m_shaderTrans.attribLoc[0]);
|
||||
glEnableVertexAttribArray(m_shaderTrans.attribLoc[1]);
|
||||
|
||||
glVertexAttribPointer(m_shaderTrans.attribLoc[0], 3, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, verts));
|
||||
glVertexAttribPointer(m_shaderTrans.attribLoc[1], 2, GL_FLOAT, GL_FALSE, sizeof(FBVertex), (void*)offsetof(FBVertex, texCoords));
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(m_shaderTrans.attribLoc[0]);
|
||||
glDisableVertexAttribArray(m_shaderTrans.attribLoc[1]);
|
||||
|
||||
m_shaderTrans.DisableShader();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,149 @@
|
||||
#include "R3DScrollFog.h"
|
||||
#include "Graphics/Shader.h"
|
||||
#include "Mat4.h"
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
namespace New3D {
|
||||
|
||||
#ifndef __ANDROID__
|
||||
#include "Graphics/Shader.h"
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
namespace {
|
||||
static void LogShaderError(GLuint shader, const char* label)
|
||||
{
|
||||
GLint ok = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
|
||||
if (ok == GL_TRUE) return;
|
||||
GLint len = 0;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
|
||||
if (len <= 0) return;
|
||||
std::string msg;
|
||||
msg.resize(static_cast<size_t>(len));
|
||||
GLsizei written = 0;
|
||||
glGetShaderInfoLog(shader, len, &written, msg.data());
|
||||
fprintf(stderr, "R3DScrollFog %s compile error: %s\n", label ? label : "shader", msg.c_str());
|
||||
}
|
||||
|
||||
static void LogProgramError(GLuint program)
|
||||
{
|
||||
GLint ok = 0;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &ok);
|
||||
if (ok == GL_TRUE) return;
|
||||
GLint len = 0;
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
|
||||
if (len <= 0) return;
|
||||
std::string msg;
|
||||
msg.resize(static_cast<size_t>(len));
|
||||
GLsizei written = 0;
|
||||
glGetProgramInfoLog(program, len, &written, msg.data());
|
||||
fprintf(stderr, "R3DScrollFog link error: %s\n", msg.c_str());
|
||||
}
|
||||
|
||||
static bool CompileShaderProgram(GLuint* programOut, GLuint* vsOut, GLuint* fsOut, const char* vsSrc, const char* fsSrc)
|
||||
{
|
||||
if (!programOut || !vsOut || !fsOut) return false;
|
||||
*programOut = 0;
|
||||
*vsOut = 0;
|
||||
*fsOut = 0;
|
||||
|
||||
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vs, 1, &vsSrc, nullptr);
|
||||
glCompileShader(vs);
|
||||
LogShaderError(vs, "vertex");
|
||||
|
||||
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fs, 1, &fsSrc, nullptr);
|
||||
glCompileShader(fs);
|
||||
LogShaderError(fs, "fragment");
|
||||
|
||||
GLuint program = glCreateProgram();
|
||||
glAttachShader(program, vs);
|
||||
glAttachShader(program, fs);
|
||||
glLinkProgram(program);
|
||||
LogProgramError(program);
|
||||
|
||||
GLint ok = 0;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &ok);
|
||||
if (ok != GL_TRUE) {
|
||||
glDeleteProgram(program);
|
||||
glDeleteShader(vs);
|
||||
glDeleteShader(fs);
|
||||
return false;
|
||||
}
|
||||
|
||||
*programOut = program;
|
||||
*vsOut = vs;
|
||||
*fsOut = fs;
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static const char *vertexShaderFog = R"glsl(
|
||||
|
||||
#version 300 es
|
||||
precision highp float;
|
||||
|
||||
uniform mat4 mvp;
|
||||
in vec3 inVertex;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = mvp * vec4(inVertex,1.0);
|
||||
}
|
||||
|
||||
)glsl";
|
||||
|
||||
static const char *fragmentShaderFog = R"glsl(
|
||||
|
||||
#version 300 es
|
||||
precision mediump float;
|
||||
|
||||
uniform float fogAttenuation;
|
||||
uniform float fogAmbient;
|
||||
uniform vec4 fogColour;
|
||||
uniform vec3 spotFogColor;
|
||||
uniform vec4 spotEllipse;
|
||||
|
||||
out vec4 oColor;
|
||||
|
||||
// Spotlight on fog
|
||||
float ellipse;
|
||||
vec2 position, size;
|
||||
vec3 lSpotFogColor;
|
||||
|
||||
// Scroll fog
|
||||
vec3 lFogColor;
|
||||
vec4 scrollFog;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Scroll fog base color
|
||||
lFogColor = fogColour.rgb * fogAmbient;
|
||||
|
||||
// Spotlight on fog (area)
|
||||
position = spotEllipse.xy;
|
||||
size = spotEllipse.zw;
|
||||
ellipse = length((gl_FragCoord.xy - position) / size);
|
||||
ellipse = ellipse * ellipse; // decay rate = square of distance from center
|
||||
ellipse = 1.0 - ellipse; // invert
|
||||
ellipse = max(0.0, ellipse); // clamp
|
||||
|
||||
// Spotlight on fog (color)
|
||||
lSpotFogColor = mix(spotFogColor * ellipse * fogColour.rgb, vec3(0.0), fogAttenuation);
|
||||
|
||||
// Scroll fog density
|
||||
scrollFog = vec4(lFogColor + lSpotFogColor, fogColour.a);
|
||||
|
||||
// Final Color
|
||||
oColor = scrollFog;
|
||||
}
|
||||
|
||||
)glsl";
|
||||
#else
|
||||
static const char *vertexShaderFog = R"glsl(
|
||||
|
||||
#version 120
|
||||
@@ -62,6 +202,7 @@ void main()
|
||||
}
|
||||
|
||||
)glsl";
|
||||
#endif
|
||||
|
||||
|
||||
R3DScrollFog::R3DScrollFog(const Util::Config::Node &config)
|
||||
@@ -112,10 +253,10 @@ void R3DScrollFog::DrawScrollFog(float rgba[4], float attenuation, float ambient
|
||||
glUniform4f (m_locSpotEllipse, spotEllipse[0], spotEllipse[1], spotEllipse[2], spotEllipse[3]);
|
||||
glUniformMatrix4fv (m_locMVP, 1, GL_FALSE, mvp);
|
||||
|
||||
glEnableVertexAttribArray (0);
|
||||
glEnableVertexAttribArray (m_locInVertex);
|
||||
glVertexAttribPointer (m_locInVertex, 3, GL_FLOAT, GL_FALSE, sizeof(SFVertex), 0);
|
||||
glDrawArrays (GL_TRIANGLES, 0, 6);
|
||||
glDisableVertexAttribArray (0);
|
||||
glDisableVertexAttribArray (m_locInVertex);
|
||||
|
||||
glUseProgram (0);
|
||||
m_vbo.Bind (false);
|
||||
@@ -126,7 +267,26 @@ void R3DScrollFog::DrawScrollFog(float rgba[4], float attenuation, float ambient
|
||||
|
||||
void R3DScrollFog::AllocResources()
|
||||
{
|
||||
bool success = LoadShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, m_config["VertexShaderFog"].ValueAs<std::string>(), m_config["FragmentShaderFog"].ValueAs<std::string>(), vertexShaderFog, fragmentShaderFog);
|
||||
#ifdef __ANDROID__
|
||||
bool success = CompileShaderProgram(&m_shaderProgram, &m_vertexShader, &m_fragmentShader, vertexShaderFog, fragmentShaderFog);
|
||||
#else
|
||||
bool success =
|
||||
LoadShaderProgram(
|
||||
&m_shaderProgram,
|
||||
&m_vertexShader,
|
||||
&m_fragmentShader,
|
||||
m_config["VertexShaderFog"].ValueAsDefault<std::string>(""),
|
||||
m_config["FragmentShaderFog"].ValueAsDefault<std::string>(""),
|
||||
vertexShaderFog,
|
||||
fragmentShaderFog
|
||||
);
|
||||
#endif
|
||||
if (!success) {
|
||||
m_shaderProgram = 0;
|
||||
m_vertexShader = 0;
|
||||
m_fragmentShader = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m_locMVP = glGetUniformLocation(m_shaderProgram, "mvp");
|
||||
m_locFogColour = glGetUniformLocation(m_shaderProgram, "fogColour");
|
||||
@@ -143,7 +303,16 @@ void R3DScrollFog::AllocResources()
|
||||
void R3DScrollFog::DeallocResources()
|
||||
{
|
||||
if (m_shaderProgram) {
|
||||
#ifdef __ANDROID__
|
||||
glUseProgram(0);
|
||||
glDetachShader(m_shaderProgram, m_vertexShader);
|
||||
glDetachShader(m_shaderProgram, m_fragmentShader);
|
||||
glDeleteShader(m_vertexShader);
|
||||
glDeleteShader(m_fragmentShader);
|
||||
glDeleteProgram(m_shaderProgram);
|
||||
#else
|
||||
DestroyShaderProgram(m_shaderProgram, m_vertexShader, m_fragmentShader);
|
||||
#endif
|
||||
}
|
||||
|
||||
m_shaderProgram = 0;
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#ifndef _R3DSCROLLFOG_H_
|
||||
#define _R3DSCROLLFOG_H_
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <GLES3/gl3.h>
|
||||
#else
|
||||
#include <GL/glew.h>
|
||||
#endif
|
||||
|
||||
#include "Util/NewConfig.h"
|
||||
#include "VBO.h"
|
||||
|
||||
@@ -61,4 +67,4 @@ private:
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,8 @@ YResolution = 384
|
||||
VSync = 1
|
||||
WideScreen = 0
|
||||
WideBackground = 0
|
||||
; Enhanced Real3D compositing (FBO transparency + scroll fog). More accurate but may be slower.
|
||||
New3DAccurate = 0
|
||||
|
||||
; Input system (Android uses SDL input backend)
|
||||
InputSystem = sdl
|
||||
|
||||
@@ -116,11 +116,14 @@ add_library(super3 SHARED
|
||||
gles_stub_render3d.cpp
|
||||
render2d_android.cpp
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/Mat4.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/GLSLShader.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/Model.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/New3D.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/PolyHeader.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/R3DFloat.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/R3DFrameBuffers.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/R3DShader.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/R3DScrollFog.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/Texture.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/TextureSheet.cpp"
|
||||
"${REPO_ROOT}/Src/Graphics/New3D/VBO.cpp"
|
||||
|
||||
@@ -174,6 +174,7 @@ struct Super3Host {
|
||||
config.Set("MusicVolume", "200");
|
||||
config.Set("LegacySoundDSP", false);
|
||||
config.Set("New3DEngine", false);
|
||||
config.Set("New3DAccurate", false);
|
||||
config.Set("QuadRendering", false);
|
||||
config.Set("FlipStereo", false);
|
||||
// The core expects this node to exist (throws std::range_error otherwise).
|
||||
@@ -573,6 +574,7 @@ struct Super3Host {
|
||||
return !!new3d;
|
||||
|
||||
SDL_Log("Initializing New3D (GLES) ...");
|
||||
SDL_Log("New3DAccurate=%d", config["New3DAccurate"].ValueAsDefault<bool>(false) ? 1 : 0);
|
||||
new3d = std::make_unique<New3D::CNew3D>(config, game.name);
|
||||
if (new3d->Init(xOff, yOff, xRes, yRes, totalXRes, totalYRes) != 0)
|
||||
{
|
||||
|
||||
@@ -45,6 +45,7 @@ class MainActivity : AppCompatActivity() {
|
||||
private lateinit var btnResolutionMatchDevice: MaterialButton
|
||||
private lateinit var btnWidescreen: MaterialButton
|
||||
private lateinit var btnWideBackground: MaterialButton
|
||||
private lateinit var btnEnhancedReal3d: MaterialButton
|
||||
|
||||
private lateinit var gamesAdapter: GamesAdapter
|
||||
|
||||
@@ -62,6 +63,7 @@ class MainActivity : AppCompatActivity() {
|
||||
val yResolution: Int,
|
||||
val wideScreen: Boolean,
|
||||
val wideBackground: Boolean,
|
||||
val enhancedReal3d: Boolean,
|
||||
val matchDevice: Boolean,
|
||||
)
|
||||
|
||||
@@ -125,6 +127,7 @@ class MainActivity : AppCompatActivity() {
|
||||
btnResolutionMatchDevice = headerView.findViewById(R.id.btn_resolution_match_device)
|
||||
btnWidescreen = headerView.findViewById(R.id.btn_widescreen)
|
||||
btnWideBackground = headerView.findViewById(R.id.btn_wide_background)
|
||||
btnEnhancedReal3d = headerView.findViewById(R.id.btn_enhanced_real3d)
|
||||
val btnShowTouchControls: MaterialButton = headerView.findViewById(R.id.btn_show_touch_controls)
|
||||
val btnShowShifterOverlay: MaterialButton = headerView.findViewById(R.id.btn_show_shifter_overlay)
|
||||
|
||||
@@ -230,7 +233,8 @@ class MainActivity : AppCompatActivity() {
|
||||
val wideScreen = prefs.getBoolean("video_wideScreen", false)
|
||||
val wideBackground = prefs.getBoolean("video_wideBackground", false)
|
||||
val matchDevice = prefs.getBoolean("video_matchDevice", false)
|
||||
return VideoSettings(x, y, wideScreen, wideBackground, matchDevice)
|
||||
val enhancedReal3d = prefs.getBoolean("video_enhancedReal3d", false)
|
||||
return VideoSettings(x, y, wideScreen, wideBackground, enhancedReal3d, matchDevice)
|
||||
}
|
||||
|
||||
val ini = supermodelIniFile()
|
||||
@@ -238,7 +242,8 @@ class MainActivity : AppCompatActivity() {
|
||||
val y = readIniInt(ini, "YResolution") ?: 384
|
||||
val wideScreen = readIniBool(ini, "WideScreen") ?: false
|
||||
val wideBackground = readIniBool(ini, "WideBackground") ?: false
|
||||
return VideoSettings(x, y, wideScreen, wideBackground, matchDevice = false)
|
||||
val enhancedReal3d = readIniBool(ini, "New3DAccurate") ?: false
|
||||
return VideoSettings(x, y, wideScreen, wideBackground, enhancedReal3d, matchDevice = false)
|
||||
}
|
||||
|
||||
private fun saveVideoSettings(settings: VideoSettings) {
|
||||
@@ -247,6 +252,7 @@ class MainActivity : AppCompatActivity() {
|
||||
.putInt("video_yResolution", settings.yResolution)
|
||||
.putBoolean("video_wideScreen", settings.wideScreen)
|
||||
.putBoolean("video_wideBackground", settings.wideBackground)
|
||||
.putBoolean("video_enhancedReal3d", settings.enhancedReal3d)
|
||||
.putBoolean("video_matchDevice", settings.matchDevice)
|
||||
.apply()
|
||||
}
|
||||
@@ -271,6 +277,7 @@ class MainActivity : AppCompatActivity() {
|
||||
btnResolutionMatchDevice.isChecked = settings.matchDevice
|
||||
btnWidescreen.isChecked = settings.wideScreen
|
||||
btnWideBackground.isChecked = settings.wideBackground
|
||||
btnEnhancedReal3d.isChecked = settings.enhancedReal3d
|
||||
}
|
||||
|
||||
fun persistAndApply(settings: VideoSettings) {
|
||||
@@ -334,6 +341,23 @@ class MainActivity : AppCompatActivity() {
|
||||
persistAndApply(updated)
|
||||
applyUi(updated)
|
||||
}
|
||||
|
||||
btnEnhancedReal3d.setOnClickListener {
|
||||
val cur = loadVideoSettings()
|
||||
val enabled = btnEnhancedReal3d.isChecked
|
||||
val updated = cur.copy(enhancedReal3d = enabled, matchDevice = false)
|
||||
persistAndApply(updated)
|
||||
applyUi(updated)
|
||||
Toast.makeText(
|
||||
this,
|
||||
if (enabled) {
|
||||
"Enhanced Real3D enabled (restart game to apply)"
|
||||
} else {
|
||||
"Enhanced Real3D disabled (restart game to apply)"
|
||||
},
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyVideoSettingsToIni(internalRoot: File, settings: VideoSettings) {
|
||||
@@ -345,6 +369,7 @@ class MainActivity : AppCompatActivity() {
|
||||
"YResolution" to settings.yResolution.toString(),
|
||||
"WideScreen" to if (settings.wideScreen) "1" else "0",
|
||||
"WideBackground" to if (settings.wideBackground) "1" else "0",
|
||||
"New3DAccurate" to if (settings.enhancedReal3d) "1" else "0",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -101,6 +101,15 @@
|
||||
android:text="Wide background"
|
||||
style="?attr/materialButtonElevatedStyle" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_enhanced_real3d"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:checkable="true"
|
||||
android:text="Enhanced Real3D (experimental)"
|
||||
style="?attr/materialButtonElevatedStyle" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/controls_title"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
Reference in New Issue
Block a user