diff --git a/libstarlight/source/starlight/datatypes/Color.cpp b/libstarlight/source/starlight/datatypes/Color.cpp index 32d1e04..fec95a6 100644 --- a/libstarlight/source/starlight/datatypes/Color.cpp +++ b/libstarlight/source/starlight/datatypes/Color.cpp @@ -1,9 +1,13 @@ #include "Color.h" +#include + #include "starlight/_incLib/json.hpp" using starlight::Color; +const Color Color::invalid = Color(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); + 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::black = Color(0.0f, 0.0f, 0.0f); diff --git a/libstarlight/source/starlight/datatypes/Color.h b/libstarlight/source/starlight/datatypes/Color.h index 12021de..840de2d 100644 --- a/libstarlight/source/starlight/datatypes/Color.h +++ b/libstarlight/source/starlight/datatypes/Color.h @@ -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 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 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)); } + 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 white; static const Color black; diff --git a/libstarlight/source/starlight/datatypes/Vector2.h b/libstarlight/source/starlight/datatypes/Vector2.h index c28bc0c..fcd2759 100644 --- a/libstarlight/source/starlight/datatypes/Vector2.h +++ b/libstarlight/source/starlight/datatypes/Vector2.h @@ -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 bool Valid() const { return x == x && y == y; } inline explicit operator bool() const { return x == x && y == y; } static const Vector2 invalid; diff --git a/libstarlight/source/starlight/gfx/RenderCore.cpp b/libstarlight/source/starlight/gfx/RenderCore.cpp index 195f063..fecb35e 100644 --- a/libstarlight/source/starlight/gfx/RenderCore.cpp +++ b/libstarlight/source/starlight/gfx/RenderCore.cpp @@ -16,6 +16,7 @@ using starlight::Vector2; using starlight::VRect; using starlight::Color; using starlight::util::WorkerThread; +using starlight::gfx::BlendMode; using starlight::gfx::CTexture; using starlight::gfx::CRenderTarget; using starlight::gfx::RenderCore; @@ -144,25 +145,49 @@ void RenderCore::EndFrame() { 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_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_CONSTANT, 0); - 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);//REPLACE); // let's see... - C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE); + ApplyBlendMode(env, mode); 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_TexEnvSrc(env, C3D_Both, GPU_CONSTANT, 0, 0); - C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0); - 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); + ApplyBlendMode(env, mode); C3D_TexEnvColor(env, color.Premultiplied()); } @@ -263,7 +288,7 @@ CRenderTarget::CRenderTarget(int width, int height, bool forceExact) { //Clear(Color::transparent); //RenderCore::BindTexture(&tex, Color::white); //C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, 0, 0); - //C3D_RenderTargetSetClear(tgt, static_cast(0), 0, 0); + C3D_RenderTargetSetClear(tgt, static_cast(0), 0, 0); } CRenderTarget::~CRenderTarget() { @@ -279,7 +304,7 @@ void CRenderTarget::Clear(Color color) { } void CRenderTarget::BindTarget() { - if (true || clearColor) { // clear if color valid + if (clearColor.Valid()) { // clear if color valid unsigned int c = clearColor; c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness //C3D_RenderTargetSetClear(tgt, static_cast(0), c, 0); @@ -288,6 +313,13 @@ void CRenderTarget::BindTarget() { } C3D_FrameDrawOn(tgt); 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) { diff --git a/libstarlight/source/starlight/gfx/RenderCore.h b/libstarlight/source/starlight/gfx/RenderCore.h index bbd00dd..bd0a1dc 100644 --- a/libstarlight/source/starlight/gfx/RenderCore.h +++ b/libstarlight/source/starlight/gfx/RenderCore.h @@ -14,6 +14,13 @@ namespace starlight { namespace gfx { class RenderCore; + enum class BlendMode { + Blend, + Mask, + Replace, + + Normal = Blend + }; class CTexture { protected: @@ -33,6 +40,7 @@ namespace starlight { C3D_RenderTarget* tgt; C3D_Tex tex; Color clearColor = Color::transparent; + bool firstClearDone = false; public: C3D_Mtx projection; @@ -62,8 +70,8 @@ namespace starlight { static void BeginFrame(); static void EndFrame(); - static void BindTexture(C3D_Tex* tex, const Color& color); - static void BindColor(const Color& color); + static void BindTexture(C3D_Tex* tex, const Color& color, BlendMode mode = BlendMode::Normal); + 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 Vector2& anchor, float angle, const VRect& src); diff --git a/libstarlight/todo.txt b/libstarlight/todo.txt index b283e71..6453a53 100644 --- a/libstarlight/todo.txt +++ b/libstarlight/todo.txt @@ -2,7 +2,13 @@ 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 figure out what (else) to put on the left side of the keyboard (opposite backspace and enter) temporary drawable loading, local themeref, discard etc. @@ -24,6 +30,7 @@ roadmap to v0.5.1 { } } then by v0.5.5 { 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" { 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 {