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 <limits>
#include "starlight/_incLib/json.hpp"
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::white = Color(1.0f, 1.0f, 1.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 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;

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 bool Valid() const { return x == x && y == y; }
inline explicit operator bool() const { return x == x && y == y; }
static const Vector2 invalid;

View File

@ -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<C3D_ClearBits>(0), 0, 0);
C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(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<C3D_ClearBits>(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) {

View File

@ -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);

View File

@ -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 {