blend modes on bind, workaround for the clear bug (just shove a quad there in replace mode)

This commit is contained in:
zetaPRIME 2017-05-02 16:27:10 -04:00
parent 144510b4e7
commit c4a75355eb
6 changed files with 74 additions and 16 deletions

View File

@ -1,9 +1,13 @@
#include "Color.h" #include "Color.h"
#include <limits>
#include "starlight/_incLib/json.hpp" #include "starlight/_incLib/json.hpp"
using starlight::Color; using starlight::Color;
const Color Color::invalid = Color(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN());
const Color Color::transparent = Color(0.0f, 0.0f, 0.0f, 0.0f); const Color Color::transparent = Color(0.0f, 0.0f, 0.0f, 0.0f);
const Color Color::white = Color(1.0f, 1.0f, 1.0f); const Color Color::white = Color(1.0f, 1.0f, 1.0f);
const Color Color::black = Color(0.0f, 0.0f, 0.0f); const Color Color::black = Color(0.0f, 0.0f, 0.0f);

View File

@ -25,11 +25,17 @@ namespace starlight {
inline bool operator != (const Color& o) const { return r != o.r || g != o.g || b != o.b || a != o.a; } inline bool operator != (const Color& o) const { return r != o.r || g != o.g || b != o.b || a != o.a; }
inline Color operator * (const Color& o) const { return Color(r * o.r, g * o.g, b * o.b, a * o.a); } inline Color operator * (const Color& o) const { return Color(r * o.r, g * o.g, b * o.b, a * o.a); }
//inline Color operator * (const float m) const { return Color(r * m, g * m, b * m, a * m); }
// hmm. I guess this will do ¯\_(ツ)_/¯ don't really want to force cstdint // hmm. I guess this will do ¯\_(ツ)_/¯ don't really want to force cstdint
inline operator unsigned int() const { return (((((int)(a*255))&0xFF)<<24) | ((((int)(b*255))&0xFF)<<16) | ((((int)(g*255))&0xFF)<<8) | ((((int)(r*255))&0xFF)<<0)); } inline operator unsigned int() const { return (((((int)(a*255))&0xFF)<<24) | ((((int)(b*255))&0xFF)<<16) | ((((int)(g*255))&0xFF)<<8) | ((((int)(r*255))&0xFF)<<0)); }
// premult: inline operator unsigned int() const { return (((((int)(a*255))&0xFF)<<24) | ((((int)(a*b*255))&0xFF)<<16) | ((((int)(a*g*255))&0xFF)<<8) | ((((int)(a*r*255))&0xFF)<<0)); } // premult: inline operator unsigned int() const { return (((((int)(a*255))&0xFF)<<24) | ((((int)(a*b*255))&0xFF)<<16) | ((((int)(a*g*255))&0xFF)<<8) | ((((int)(a*r*255))&0xFF)<<0)); }
inline bool Valid() const { return a == a && r == r && g == g && b == b; }
inline explicit operator bool() const { return a == a && r == r && g == g && b == b; }
static const Color invalid;
static const Color transparent; static const Color transparent;
static const Color white; static const Color white;
static const Color black; static const Color black;

View File

@ -47,7 +47,8 @@ namespace starlight {
inline Vector2 & operator += (const Vector2 & o) { x += o.x; y += o.y; return *this; } inline Vector2 & operator += (const Vector2 & o) { x += o.x; y += o.y; return *this; }
inline Vector2 & operator -= (const Vector2 & o) { x -= o.x; y -= o.y; return *this; } inline Vector2 & operator -= (const Vector2 & o) { x -= o.x; y -= o.y; return *this; }
inline Vector2 & operator *= (const Vector2 & o) { x *= o.x; y *= o.y; return *this; } inline Vector2 & operator *= (const Vector2 & o) { x *= o.x; y *= o.y; return *this; }
inline bool Valid() const { return x == x && y == y; }
inline explicit operator bool() const { return x == x && y == y; } inline explicit operator bool() const { return x == x && y == y; }
static const Vector2 invalid; static const Vector2 invalid;

View File

@ -16,6 +16,7 @@ using starlight::Vector2;
using starlight::VRect; using starlight::VRect;
using starlight::Color; using starlight::Color;
using starlight::util::WorkerThread; using starlight::util::WorkerThread;
using starlight::gfx::BlendMode;
using starlight::gfx::CTexture; using starlight::gfx::CTexture;
using starlight::gfx::CRenderTarget; using starlight::gfx::CRenderTarget;
using starlight::gfx::RenderCore; using starlight::gfx::RenderCore;
@ -144,25 +145,49 @@ void RenderCore::EndFrame() {
C3D_FrameEnd(0); C3D_FrameEnd(0);
} }
void RenderCore::BindTexture(C3D_Tex* tex, const Color& color) { namespace {
void ApplyBlendMode(C3D_TexEnv* env, BlendMode mode) {
switch(mode) {
case BlendMode::Mask: // TODO: actually implement masking! this is just a copy of Blend right now
C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0);
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA, 0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE);
C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
break;
case BlendMode::Replace:
C3D_AlphaBlend(GPU_BLEND_MAX, GPU_BLEND_MAX, GPU_ONE, GPU_ZERO, GPU_ONE, GPU_ZERO); // flat replace
C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0);
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA, 0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);
C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE);
break;
default:
case BlendMode::Blend:
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); // premult
C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0);
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA, 0); // for color, the second op was 0... but that's the same value so whatever
C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE); // and for color, this was REPLACE, not sure if that actually matters
C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
break;
}
}
}
void RenderCore::BindTexture(C3D_Tex* tex, const Color& color, BlendMode mode) {
C3D_TexBind(0, tex); // 0 should be correct C3D_TexBind(0, tex); // 0 should be correct
C3D_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_CONSTANT, 0); C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_CONSTANT, 0);
C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0); ApplyBlendMode(env, mode);
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA, 0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE);//REPLACE); // let's see...
C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
C3D_TexEnvColor(env, color.Premultiplied()); C3D_TexEnvColor(env, color.Premultiplied());
} }
void RenderCore::BindColor(const Color& color) { void RenderCore::BindColor(const Color& color, BlendMode mode) {
C3D_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvSrc(env, C3D_Both, GPU_CONSTANT, 0, 0); C3D_TexEnvSrc(env, C3D_Both, GPU_CONSTANT, 0, 0);
C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0); ApplyBlendMode(env, mode);
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, 0, 0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);//REPLACE); // let's see...
C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE);
C3D_TexEnvColor(env, color.Premultiplied()); C3D_TexEnvColor(env, color.Premultiplied());
} }
@ -263,7 +288,7 @@ CRenderTarget::CRenderTarget(int width, int height, bool forceExact) {
//Clear(Color::transparent); //Clear(Color::transparent);
//RenderCore::BindTexture(&tex, Color::white); //RenderCore::BindTexture(&tex, Color::white);
//C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, 0, 0); //C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, 0, 0);
//C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(0), 0, 0); C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(0), 0, 0);
} }
CRenderTarget::~CRenderTarget() { CRenderTarget::~CRenderTarget() {
@ -279,7 +304,7 @@ void CRenderTarget::Clear(Color color) {
} }
void CRenderTarget::BindTarget() { void CRenderTarget::BindTarget() {
if (true || clearColor) { // clear if color valid if (clearColor.Valid()) { // clear if color valid
unsigned int c = clearColor; unsigned int c = clearColor;
c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness
//C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(0), c, 0); //C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(0), c, 0);
@ -288,6 +313,13 @@ void CRenderTarget::BindTarget() {
} }
C3D_FrameDrawOn(tgt); C3D_FrameDrawOn(tgt);
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, sLocProjection, &projection); C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, sLocProjection, &projection);
if (!firstClearDone) { firstClearDone = true; // workaround for faulty clearing; just draw a quad in replace mode to force the matter!
if (clearColor.Valid()) {
RenderCore::BindColor(clearColor, BlendMode::Replace);
RenderCore::DrawQuad(VRect(Vector2::zero, txSize), VRect::zero, false);
}
}
} }
void CRenderTarget::Bind(Color color) { void CRenderTarget::Bind(Color color) {

View File

@ -14,6 +14,13 @@
namespace starlight { namespace starlight {
namespace gfx { namespace gfx {
class RenderCore; class RenderCore;
enum class BlendMode {
Blend,
Mask,
Replace,
Normal = Blend
};
class CTexture { class CTexture {
protected: protected:
@ -33,6 +40,7 @@ namespace starlight {
C3D_RenderTarget* tgt; C3D_RenderTarget* tgt;
C3D_Tex tex; C3D_Tex tex;
Color clearColor = Color::transparent; Color clearColor = Color::transparent;
bool firstClearDone = false;
public: public:
C3D_Mtx projection; C3D_Mtx projection;
@ -62,8 +70,8 @@ namespace starlight {
static void BeginFrame(); static void BeginFrame();
static void EndFrame(); static void EndFrame();
static void BindTexture(C3D_Tex* tex, const Color& color); static void BindTexture(C3D_Tex* tex, const Color& color, BlendMode mode = BlendMode::Normal);
static void BindColor(const Color& color); static void BindColor(const Color& color, BlendMode mode = BlendMode::Normal);
static void DrawQuad(const VRect& rect, const VRect& src, bool noSnap = false); static void DrawQuad(const VRect& rect, const VRect& src, bool noSnap = false);
static void DrawQuad(const VRect& rect, const Vector2& anchor, float angle, const VRect& src); static void DrawQuad(const VRect& rect, const Vector2& anchor, float angle, const VRect& src);

View File

@ -2,7 +2,13 @@
roadmap to v0.5.1 { roadmap to v0.5.1 {
figure out how to fix the clear bug - clear bug workaround implemented
^ maybe replace clearing with the workaround entirely?
implement more blend modes {
- flat replace
masking
}
- fix the hang on osk when pressing (L|R)+up+left - fix the hang on osk when pressing (L|R)+up+left
figure out what (else) to put on the left side of the keyboard (opposite backspace and enter) figure out what (else) to put on the left side of the keyboard (opposite backspace and enter)
temporary drawable loading, local themeref, discard etc. temporary drawable loading, local themeref, discard etc.
@ -24,6 +30,7 @@ roadmap to v0.5.1 {
} }
} then by v0.5.5 { } then by v0.5.5 {
event propagation system of some sort; threadsafe to whatever extent is needed on 3DS event propagation system of some sort; threadsafe to whatever extent is needed on 3DS
figure out how to *actually* fix the clear bug...?
} then consider these before 1.0 "gold" { } then consider these before 1.0 "gold" {
make closing forms a bit less finicky (add them to a separate list and let the Application remove them from the list) make closing forms a bit less finicky (add them to a separate list and let the Application remove them from the list)
garbage collection for not-recently-used theme assets { garbage collection for not-recently-used theme assets {