From c74fec040df8b09c731e0930b2a760228bcb8dfd Mon Sep 17 00:00:00 2001 From: Hugh Sanderson Date: Thu, 28 Mar 2024 14:06:22 +0800 Subject: [PATCH] Add initial support for LCD font quality --- include/nme/Pixel.h | 14 +++ project/include/Display.h | 2 + project/include/Font.h | 2 +- project/include/Graphics.h | 3 + project/include/HardwareImpl.h | 8 +- project/src/common/ExternalInterface.cpp | 15 ++- project/src/common/Font.cpp | 6 +- project/src/common/Stage.cpp | 17 +++ project/src/common/SurfaceBlit.cpp | 85 ++++++++++++- project/src/common/TextField.cpp | 3 +- project/src/opengl/OGLShaders.cpp | 102 +++++++++++----- project/src/opengl/OGLShaders.h | 3 +- project/src/opengl/OpenGLContext.cpp | 112 ++++++++++++------ .../src/software-renderer/TileRenderer.cpp | 4 +- project/src/windows/GDIFont.cpp | 42 +++++-- samples/02-Text/Sample.hx | 48 +++++--- src/nme/app/Window.hx | 8 ++ src/nme/display/Stage.hx | 2 + 18 files changed, 372 insertions(+), 104 deletions(-) diff --git a/include/nme/Pixel.h b/include/nme/Pixel.h index e81219426..399eb0ff1 100644 --- a/include/nme/Pixel.h +++ b/include/nme/Pixel.h @@ -86,6 +86,15 @@ struct BGRA inline BGRA() { } inline BGRA(int inRGBA) { ival = inRGBA; } + inline BGRA(int inRGBA,bool withPrem) { + if (withPrem && PREM) { + a = (inRGBA>>24); + r = gPremAlphaLut[a][(inRGBA>>16)&0xff ]; + g = gPremAlphaLut[a][(inRGBA>>8)&0xff ]; + b = gPremAlphaLut[a][(inRGBA)&0xff ]; + } else + ival = inRGBA; + } inline BGRA(int inRGB,int inA) { ival = (inRGB & 0xffffff) | (inA<<24); } inline BGRA(int inRGB,float inA) { @@ -109,6 +118,7 @@ struct BGRA inline int getB() const { return PREM ? gUnPremAlphaLut[a][b] : b; } inline int getLuma() const { return PREM ? gUnPremAlphaLut[a][(r+(g<<1)+b)>>2] : (r+(g<<1)+b)>>2; } + inline void setAlphaOnly(Uint8 val) { a = val; } inline void setAlpha(Uint8 val) { if (PREM && val!=a) @@ -198,6 +208,7 @@ struct RGB inline int getB() const { return b; } + inline void setAlphaOnly(Uint8 val) { } inline void setAlpha(Uint8 val) { } inline void setLuma(Uint8 val) { r = g = b = val; } @@ -268,6 +279,7 @@ struct AlphaPixel + inline void setAlphaOnly(Uint8 val) { a = val; } inline void setAlpha(Uint8 val) { a = val; } inline void setLuma(Uint8 val) { } @@ -302,6 +314,7 @@ struct LumaPixel + inline void setAlphaOnly(int val) { } inline void setAlpha(int val) { } inline void setLuma(int val) { luma = val; } @@ -335,6 +348,7 @@ struct LumaAlphaPixel + inline void setAlphaOnly(Uint8 val) { a = val; } inline void setAlpha(Uint8 val) { a = val; } inline void setLuma(Uint8 val) { luma = val; } diff --git a/project/include/Display.h b/project/include/Display.h index 8dfab2a88..90919ebdb 100644 --- a/project/include/Display.h +++ b/project/include/Display.h @@ -408,8 +408,10 @@ class Stage : public DisplayObjectContainer virtual void RenderStage(); virtual void EndRenderStage(); virtual void ResizeWindow(int inWidth, int inHeight) {}; + virtual HardwareRenderer *getHardwareRenderer(); virtual bool isOpenGL() const = 0; + virtual bool hasHardwareLcdFonts() const; virtual int getWindowFrameBufferId() { return 0; }; void SetEventHandler(EventHandler inHander,void *inUserData); diff --git a/project/include/Font.h b/project/include/Font.h index d77d974b3..a5deb2c5e 100644 --- a/project/include/Font.h +++ b/project/include/Font.h @@ -187,7 +187,7 @@ class FontFace virtual void UpdateMetrics(TextLineMetrics &ioMetrics)=0; virtual int Height()=0; virtual bool IsNative() { return false; } - virtual bool WantRGB() { return false; } + virtual PixelFormat getImageFormat() const { return pfAlpha; } }; diff --git a/project/include/Graphics.h b/project/include/Graphics.h index cb01c98f1..b87c3ff64 100644 --- a/project/include/Graphics.h +++ b/project/include/Graphics.h @@ -408,6 +408,9 @@ enum BlendMode bmTintedInner, // Used for rendering coloured tiles, with add bmTintedAdd, + + // Used for rendering ClearType text + bmComponentAlpha, }; class ColorTransform diff --git a/project/include/HardwareImpl.h b/project/include/HardwareImpl.h index e592a1d3b..edad85997 100644 --- a/project/include/HardwareImpl.h +++ b/project/include/HardwareImpl.h @@ -20,8 +20,9 @@ enum PROG_COLOUR_OFFSET = 0x0080, PROG_4D_INPUT = 0x0100, PROG_PREM_ALPHA = 0x0200, + PROG_COMP_ALPHA = 0x0400, - PROG_COUNT = 0x0400, + PROG_COUNT = 0x0800, }; inline unsigned int getProgId( const DrawElement &element, const ColorTransform *ctrans) @@ -58,6 +59,11 @@ inline unsigned int getProgId( const DrawElement &element, const ColorTransform if (ctrans && ctrans->HasOffset()) progId |= PROG_COLOUR_OFFSET; } + if (element.mBlendMode == bmComponentAlpha) + { + progId |= PROG_COMP_ALPHA; + } + return progId; } diff --git a/project/src/common/ExternalInterface.cpp b/project/src/common/ExternalInterface.cpp index 896f3fe5d..18096272a 100644 --- a/project/src/common/ExternalInterface.cpp +++ b/project/src/common/ExternalInterface.cpp @@ -1803,7 +1803,20 @@ bool nme_stage_is_opengl(value inStage) return false; } DEFINE_PRIME1(nme_stage_is_opengl); - + +bool nme_stage_has_hardware_lcd_fonts(value inStage) +{ + Stage *stage; + if (AbstractToObject(inStage,stage)) + { + return stage->hasHardwareLcdFonts(); + } + return false; +} +DEFINE_PRIME1(nme_stage_has_hardware_lcd_fonts); + + + namespace nme { void AndroidRequestRender(); } void nme_stage_request_render() diff --git a/project/src/common/Font.cpp b/project/src/common/Font.cpp index 0feeaa7b2..d5c8affed 100644 --- a/project/src/common/Font.cpp +++ b/project/src/common/Font.cpp @@ -68,7 +68,7 @@ class CFFIFont : public FontFace mIsRGB = val_bool( val_field(inHandle, _id_isRGB) ); } - bool WantRGB() { return true; } + PixelFormat getImageFormat() const { return pfBGRA; } bool GetGlyphInfo(int inChar, int &outW, int &outH, int &outAdvance, int &outOx, int &outOy) @@ -222,7 +222,7 @@ Tile Font::GetGlyph(int inCharacter,int &outAdvance) int w = h; while(wWantRGB() ? pfBGRA : pfAlpha; + PixelFormat pf = mFace->getImageFormat(); Tilesheet *sheet = new Tilesheet(w,h,pf,true); sheet->GetSurface().Clear(0); mCurrentSheet = mSheets.size(); @@ -247,6 +247,7 @@ Tile Font::GetGlyph(int inCharacter,int &outAdvance) RenderTarget target = tile.mSurface->BeginRender(tile.mRect); if (use_default) { + // TODO - non-alpha images for(int y=0; yRenderGlyph(inCharacter,target); tile.mSurface->EndRender(); + outAdvance = glyph.advance; return tile; } diff --git a/project/src/common/Stage.cpp b/project/src/common/Stage.cpp index 0b7945834..da60b93e8 100644 --- a/project/src/common/Stage.cpp +++ b/project/src/common/Stage.cpp @@ -91,6 +91,23 @@ void Stage::SetNextWakeDelay(double inNextWake) mNextWake = inNextWake + GetTimeStamp(); } +HardwareRenderer *Stage::getHardwareRenderer() +{ + Surface *surface = GetPrimarySurface(); + if (!surface) + return nullptr; + return surface->GetHardwareRenderer(); +} + + +bool Stage::hasHardwareLcdFonts() const +{ + HardwareRenderer *hw = (const_cast(this))->getHardwareRenderer(); + if (!hw) + return false; + return hw->supportsComponentAlpha(); +} + void Stage::SetFocusObject(DisplayObject *inObj,FocusSource inSource,int inKey) { if (inObj==mFocusObject) diff --git a/project/src/common/SurfaceBlit.cpp b/project/src/common/SurfaceBlit.cpp index 64b27be00..e6a727415 100644 --- a/project/src/common/SurfaceBlit.cpp +++ b/project/src/common/SurfaceBlit.cpp @@ -14,6 +14,18 @@ struct NullMask inline uint8 MaskAlpha(const ARGB &inRGB) const { return inRGB.a; } inline uint8 MaskAlpha(const BGRPremA &inRGB) const { return inRGB.a; } inline uint8 MaskAlpha(const RGB &inRGB) const { return 255; } + + template + void maskComponentMask(const SRC &inRGB, RGB &outRGB) const + { + /* + outRGB.r = inRGB.getR(); + outRGB.g = inRGB.getG(); + outRGB.b = inRGB.getB(); + */ + } + inline void maskComponentMask(const RGB &inRGB, RGB &outRGB) const { outRGB = inRGB; } + template T Mask(T inT) const { return inT; } }; @@ -55,6 +67,24 @@ struct ImageMask return a; } + inline void maskComponentMask(const RGB &inRGB, RGB &outRgb) const + { + Uint8 *lut = gPremAlphaLut[*mRow]; + outRgb.r = lut[inRGB.r]; + outRgb.g = lut[inRGB.g]; + outRgb.b = lut[inRGB.b]; + } + + template + inline void maskComponentMask(const T &inPixel, RGB &outRgb) const + { + /* + Uint8 *lut = gPremAlphaLut[*mRow]; + outRgb.r = lut[inPixel.getR()]; + outRgb.g = lut[inPixel.getG()]; + outRgb.b = lut[inPixel.getB()]; + */ + } inline AlphaPixel Mask(const AlphaPixel &inA) const { @@ -514,13 +544,43 @@ template void ApplyInner(DEST &ioDest, SRC inSrc) } } +template void ApplyComponentAlpha(DEST &ioDest, RGB rgbMask, BGRPremA colour) +{ + int outA = std::max(std::max(rgbMask.g,rgbMask.b),rgbMask.r); + if ( outA > 2) + { + int dra = ioDest.getRAlpha(); + int dga = ioDest.getGAlpha(); + int dba = ioDest.getBAlpha(); + + ioDest.setAlphaOnly( std::max(outA, ioDest.getAlpha() ) ); + + { + int notA = 256-rgbMask.r; + ioDest.setRAlpha( ((dra*notA +colour.r*rgbMask.r )>>8) ); + } + { + int notA = 256-rgbMask.g; + ioDest.setGAlpha( ((dga*notA +colour.g*rgbMask.g )>>8) ); + } + { + int notA = 256-rgbMask.b; + ioDest.setBAlpha( ((dba*notA + colour.b*rgbMask.b )>>8) ); + } + } + +} + + + template void TBlitBlend( const DEST &outDest, SOURCE &inSrc,const MASK &inMask, - int inX, int inY, const Rect &inSrcRect, BlendMode inMode) + int inX, int inY, const Rect &inSrcRect, BlendMode inMode, + BGRPremA tint=0xffffffff) { for(int y=0;y src(inSrc->GetBase(),inSrc->GetStride()); + + if (inMask) + TBlitBlend( dest, src, ImageMask(*inMask), dx, dy, src_rect, bmComponentAlpha, tint ); + else + TBlitBlend( dest, src, NullMask(), dx, dy, src_rect, bmComponentAlpha, tint ); + } else { switch(inSrc->Format()) diff --git a/project/src/common/TextField.cpp b/project/src/common/TextField.cpp index cfed16473..024bb7df4 100644 --- a/project/src/common/TextField.cpp +++ b/project/src/common/TextField.cpp @@ -1891,7 +1891,7 @@ void TextField::Render( const RenderTarget &inTarget, const RenderState &inState { //if (fontSurface) mTiles->endTiles(); fontSurface = tile.mSurface; - mTiles->beginTiles(fontSurface,!screenGrid,bmNormal); + mTiles->beginTiles(fontSurface,!screenGrid,fontSurface->Format()==pfRGB ? bmComponentAlpha : bmNormal); } UserPoint p(pos.x+tile.mOx*fontToLocal,pos.y+tile.mOy*fontToLocal); @@ -2139,6 +2139,7 @@ void TextField::Layout(const Matrix &inMatrix, const RenderTarget *inTarget) for(int i=0;iUpdateFont(fontScale,!embedFonts,fontAaType); + mTilesDirty = true; if (charPositionDirty) { mLinesDirty = true; diff --git a/project/src/opengl/OGLShaders.cpp b/project/src/opengl/OGLShaders.cpp index 40c31d7e5..c0f9aade4 100644 --- a/project/src/opengl/OGLShaders.cpp +++ b/project/src/opengl/OGLShaders.cpp @@ -11,12 +11,13 @@ namespace nme const float one_on_255 = 1.0/255.0; -OGLProg::OGLProg(const std::string &inVertProg, const std::string &inFragProg) +OGLProg::OGLProg(const std::string &inVertProg, const std::string &inFragProg,int inProgramFlags) { mVertProg = inVertProg; mFragProg = inFragProg; mVertId = 0; mFragId = 0; + programFlags = inProgramFlags; mImageSlot = -1; mColourTransform = 0; @@ -94,9 +95,9 @@ void OGLProg::recreate() glValidateProgram(mProgramId); - GLint linked; - glGetProgramiv(mProgramId, GL_LINK_STATUS, &linked); - if (linked) + GLint linkStatus=0; + glGetProgramiv(mProgramId, GL_LINK_STATUS, &linkStatus); + if (linkStatus) { // All good ! //printf("Linked!\n"); @@ -104,29 +105,35 @@ void OGLProg::recreate() else { ELOG("Bad Link."); + } // Check the status of the compile/link int logLen = 0; glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &logLen); - if(logLen > 0) + if(logLen > 0 || !linkStatus) { // Show any errors as appropriate - char *log = new char[logLen]; - glGetProgramInfoLog(mProgramId, logLen, &logLen, log); ELOG("----"); ELOG("VERT: %s", mVertProg.c_str()); ELOG("FRAG: %s", mFragProg.c_str()); - ELOG("ERROR:\n%s\n", log); - delete [] log; - } - + if (logLen>0) + { + char *log = new char[logLen]; + glGetProgramInfoLog(mProgramId, logLen, &logLen, log); + ELOG("ERROR:\n%s\n", log); + delete [] log; + } + else + { + ELOG("no error message."); + } + glDeleteShader(mVertId); glDeleteShader(mFragId); glDeleteProgram(mProgramId); mVertId = mFragId = mProgramId = 0; } - vertexSlot = glGetAttribLocation(mProgramId, "aVertex"); textureSlot = glGetAttribLocation(mProgramId, "aTexCoord"); colourSlot = glGetAttribLocation(mProgramId, "aColourArray"); @@ -181,7 +188,6 @@ void OGLProg::setColourTransform(const ColorTransform *inTransform, uint32 inCol { rf = gf = bf = af = 1.0; } - else { rf = ( (inColor>>16) & 0xff ) * one_on_255; gf = ( (inColor>>8 ) & 0xff ) * one_on_255; @@ -269,18 +275,40 @@ void OGLProg::setGradientFocus(float inFocus) GPUProg *GPUProg::create(unsigned int inID) { - std::string vertexVars = - "uniform mat4 uTransform;\n" - "attribute vec4 aVertex;\n"; std::string vertexProg = " gl_Position = aVertex * uTransform;\n"; std::string pixelVars = ""; std::string pixelProlog = ""; + std::string blendColour = ""; #ifdef NME_GLES pixelVars = std::string("precision mediump float;\n"); #endif + std::string VIN = "attribute"; + std::string VOUT = "varying"; + std::string FIN = "varying"; + std::string VERSION = ""; + + bool dualBlend = inID & PROG_COMP_ALPHA; + std::string fragName("gl_FragColor"); + if (dualBlend) + { + fragName = "outFragColour"; + VERSION = "#version 450\n"; + pixelVars += "layout(location = 0, index = 0) out vec4 outFragColour;\n"; + pixelVars += "layout(location = 0, index = 1) out vec4 outBlendColour;\n"; + + VIN = "in"; + VOUT = "out"; + FIN = "in"; + } + + + std::string vertexVars = + "uniform mat4 uTransform;\n" + + VIN + " vec4 aVertex;\n"; + std::string fragColour = ""; @@ -299,12 +327,12 @@ GPUProg *GPUProg::create(unsigned int inID) if (inID & PROG_COLOUR_PER_VERTEX) { vertexVars += - "attribute vec4 aColourArray;\n" - "varying vec4 vColourArray;\n"; + VIN + " vec4 aColourArray;\n" + + VOUT + " vec4 vColourArray;\n"; vertexProg = " vColourArray = aColourArray;\n" + vertexProg; pixelVars += - "varying vec4 vColourArray;\n"; + FIN + " vec4 vColourArray;\n"; if (fragColour!="") fragColour += "*"; @@ -315,17 +343,21 @@ GPUProg *GPUProg::create(unsigned int inID) if (inID & PROG_TEXTURE) { vertexVars += - "attribute vec2 aTexCoord;\n" - "varying vec2 vTexCoord;\n"; + VIN + " vec2 aTexCoord;\n" + + VOUT + " vec2 vTexCoord;\n"; vertexProg = " vTexCoord = aTexCoord;\n" + vertexProg; pixelVars += - "uniform sampler2D uImage0;\n" - "varying vec2 vTexCoord;\n"; + "uniform sampler2D uImage0;\n" + + FIN + " vec2 vTexCoord;\n"; - if (!(inID & PROG_RADIAL)) + if (dualBlend) + { + blendColour = " outBlendColour = texture2D(uImage0,vTexCoord,-0.5)*outFragColour.a;\n"; + } + else if (!(inID & PROG_RADIAL)) { if (fragColour!="") fragColour += "*"; @@ -372,19 +404,20 @@ GPUProg *GPUProg::create(unsigned int inID) if (inID & PROG_NORMAL_DATA) { vertexVars += - "attribute vec2 aNormal;\n" - "varying vec2 vNormal;\n"; + VIN + " vec2 aNormal;\n" + + VOUT +" vec2 vNormal;\n"; vertexProg = " vNormal = aNormal;\n" + vertexProg; pixelVars += - "varying vec2 vNormal;\n"; + VOUT + " vec2 vNormal;\n"; } std::string vertexShader = + VERSION + vertexVars + - "void main()\n" + "void main()\n" + "{\n" + vertexProg + "}\n"; @@ -402,14 +435,23 @@ GPUProg *GPUProg::create(unsigned int inID) std::string pixelShader = + VERSION + pixelVars + "void main()\n" "{\n" + pixelProlog + - " gl_FragColor = " + fragColour + ";\n" + + " " + fragName + " = " + fragColour + ";\n" + + blendColour + "}\n"; - return new OGLProg(vertexShader, pixelShader); + /* + { + printf("vertex :\n%s\n---\n", vertexShader.c_str()); + printf("frag :\n%s\n---\n", pixelShader.c_str()); + } + */ + + return new OGLProg(vertexShader, pixelShader, inID); } diff --git a/project/src/opengl/OGLShaders.h b/project/src/opengl/OGLShaders.h index bd13a0497..76cd4713e 100644 --- a/project/src/opengl/OGLShaders.h +++ b/project/src/opengl/OGLShaders.h @@ -13,7 +13,7 @@ class OGLProg : public GPUProg { public: - OGLProg(const std::string &inVertProg, const std::string &inFragProg); + OGLProg(const std::string &inVertProg, const std::string &inFragProg, int inProgFlags); virtual ~OGLProg(); GLuint createShader(GLuint inType, const char *inShader); @@ -47,6 +47,7 @@ class OGLProg : public GPUProg GLint mASlot; GLint mFXSlot; GLint mOn2ASlot; + int programFlags; }; diff --git a/project/src/opengl/OpenGLContext.cpp b/project/src/opengl/OpenGLContext.cpp index 62be7f477..4d273a458 100644 --- a/project/src/opengl/OpenGLContext.cpp +++ b/project/src/opengl/OpenGLContext.cpp @@ -48,8 +48,44 @@ void GetGLStats(int * statsArray, int n) class OGLContext : public HardwareRenderer { + int mContextId; + ThreadId mThreadId; + + WinDC mDC; + GLCtx mOGLCtx; + + //HardwareData mBitmapBuffer; + //Texture *mBitmapTexture; + + // TODO - mutex in case finalizer is run from thread + bool mHasZombie; + QuickVec mZombieTextures; + QuickVec mZombieVbos; + QuickVec mZombiePrograms; + QuickVec mZombieShaders; + QuickVec mZombieFramebuffers; + QuickVec mZombieRenderbuffers; + QuickVec mZombieQueries; + QuickVec mZombieVertexArrays; + QuickVec mZombieTransformFeedback; + + GPUProg *mProg[PROG_COUNT]; + + + GLuint mFullTexCoordsBuffer; + GLuint mFullTexCoordsSize; + + GLuint mQuadsBuffer; + GLenum mQuadsBufferSize; + GLenum mQuadsBufferType; + + bool hasDrawBufferBlend; + + public: + + OGLContext(WinDC inDC, GLCtx inOGLCtx) { mDC = inDC; @@ -59,10 +95,31 @@ class OGLContext : public HardwareRenderer mContextId = gTextureContextVersion; mQuadsBuffer = 0; mFullTexCoordsBuffer = 0; + hasDrawBufferBlend = false; for(int i=0;i%s<\n", e.c_str() ); + if ( e=="ARB_draw_buffers_blend" || e=="GL_ARB_draw_buffers_blend" ) + hasDrawBufferBlend = true; + if (!*next || !next[1]) + break; + ext = next+1; + } + } } ~OGLContext() { @@ -208,7 +265,7 @@ class OGLContext : public HardwareRenderer bool supportsComponentAlpha() const { - return false; + return hasDrawBufferBlend; } @@ -254,6 +311,17 @@ class OGLContext : public HardwareRenderer } } + void makeCurrent() + { + #ifndef NME_GLES + #ifndef SDL_OGL + #ifndef GLFW_OGL + wglMakeCurrent(mDC,mOGLCtx); + #endif + #endif + #endif + } + void BeginRender(const Rect &inRect,bool inForHitTest) { @@ -264,13 +332,7 @@ class OGLContext : public HardwareRenderer updateContext(); } - #ifndef NME_GLES - #ifndef SDL_OGL - #ifndef GLFW_OGL - wglMakeCurrent(mDC,mOGLCtx); - #endif - #endif - #endif + makeCurrent(); if (mHasZombie) { @@ -491,6 +553,7 @@ class OGLContext : public HardwareRenderer progId &= ~PROG_PREM_ALPHA; bool persp = element.mFlags & DRAW_HAS_PERSPECTIVE; + GPUProg *prog = mProg[progId]; if (!prog) mProg[progId] = prog = GPUProg::create(progId); @@ -508,6 +571,10 @@ class OGLContext : public HardwareRenderer case bmScreen: glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR); break; + case bmComponentAlpha: + glBlendFunc(0x88F9/*GL_SRC1_COLOR*/, 0x88FA /*GL_ONE_MINUS_SRC1_COLOR*/ ); + //glBlendFunc( GL_ONE, GL_ZERO); + break; default: glBlendFunc(premAlpha ? GL_ONE : GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); } @@ -750,36 +817,7 @@ class OGLContext : public HardwareRenderer return OGLCreateTexture(inSurface,inFlags); } - int mContextId; - ThreadId mThreadId; - - WinDC mDC; - GLCtx mOGLCtx; - - //HardwareData mBitmapBuffer; - //Texture *mBitmapTexture; - // TODO - mutex in case finalizer is run from thread - bool mHasZombie; - QuickVec mZombieTextures; - QuickVec mZombieVbos; - QuickVec mZombiePrograms; - QuickVec mZombieShaders; - QuickVec mZombieFramebuffers; - QuickVec mZombieRenderbuffers; - QuickVec mZombieQueries; - QuickVec mZombieVertexArrays; - QuickVec mZombieTransformFeedback; - - GPUProg *mProg[PROG_COUNT]; - - - GLuint mFullTexCoordsBuffer; - GLuint mFullTexCoordsSize; - - GLuint mQuadsBuffer; - GLenum mQuadsBufferSize; - GLenum mQuadsBufferType; }; diff --git a/project/src/software-renderer/TileRenderer.cpp b/project/src/software-renderer/TileRenderer.cpp index df1785712..b96fab7b7 100644 --- a/project/src/software-renderer/TileRenderer.cpp +++ b/project/src/software-renderer/TileRenderer.cpp @@ -81,7 +81,7 @@ class TileRenderer : public Renderer int h = mFill->bitmapData->Height(); const UserPoint *point = (const UserPoint *)&inPath.data[inJob.mData0]; mTileData.reserve( inJob.mTileCount ); - mBlendMode = bmNormal; + mBlendMode = (BlendMode)inJob.mBlendMode; if (inJob.mBlendMode==pcBlendModeAdd) mBlendMode = bmAdd; mFlags = mFill->smooth ? 1 : 0; @@ -187,7 +187,7 @@ class TileRenderer : public Renderer { TileData &data= mTileData[i]; - BlendMode blend = data.mHasColour ? ( mBlendMode==bmAdd ? bmTintedAdd : bmTinted ): + BlendMode blend = data.mHasColour ? ( mBlendMode==bmAdd ? bmTintedAdd : mBlendMode==bmComponentAlpha ? bmComponentAlpha : bmTinted ): mBlendMode; UserPoint corner(data.mPos); UserPoint pos = inState.mTransform.mMatrix->Apply(corner.x,corner.y); diff --git a/project/src/windows/GDIFont.cpp b/project/src/windows/GDIFont.cpp index a3ae952ec..ea4f08b5e 100644 --- a/project/src/windows/GDIFont.cpp +++ b/project/src/windows/GDIFont.cpp @@ -23,8 +23,10 @@ class GDIFont : public FontFace public: bool bold; bool italic; + bool lcdOut; - GDIFont(HFONT inFont, int inHeight, bool inBold, bool inItalic) : mFont(inFont), mPixelHeight(inHeight) + GDIFont(HFONT inFont, int inHeight, bool inBold, bool inItalic, bool inLcdOut) : + mFont(inFont), mPixelHeight(inHeight), lcdOut(inLcdOut) { bold = inBold; italic = inItalic; @@ -37,6 +39,8 @@ class GDIFont : public FontFace DeleteObject(mFont); } + PixelFormat getImageFormat() const { return lcdOut ? pfRGB : pfAlpha; } + virtual bool GetGlyphInfo(int inChar, int &outW, int &outH, int &outAdvance, int &outOx, int &outOy) { @@ -59,7 +63,7 @@ class GDIFont : public FontFace if (!sGammaLUTInit) { for(int i=0;i<256;i++) - sGammaLUT[i] = pow(i/255.0,1.9)*255 + 0.5; + sGammaLUT[i] = pow(i/255.0,1.25)*255 + 0.5; sGammaLUTInit = true; } @@ -91,17 +95,35 @@ class GDIFont : public FontFace wchar_t ch = inChar; TextOutW(sgFontDC,0,0,&ch,1); - for(int y=0;yr + src->g*2 + src->b + 2) / 4]; - src++; + ARGB *src = sgDIBBits + (sgDIB_H - 1 - y)*sgDIB_W; + RGB *dest = (RGB *)outTarget.Row(y + outTarget.mRect.y) + outTarget.mRect.x; + for(int x=0;xr = src->r; + dest->g = src->g; + dest->b = src->b; + dest++; + src++; + } + } + } + else + { + for(int y=0;yr + src->g*2 + src->b + 2) / 4]; + src++; + } } } - } void UpdateMetrics(TextLineMetrics &ioMetrics) @@ -215,7 +237,7 @@ FontFace *FontFace::CreateNative(const TextFormat &inFormat,double inScale,AntiA if (!hfont) return 0; - return new GDIFont(hfont,height, inFormat.bold, inFormat.italic); + return new GDIFont(hfont,height, inFormat.bold, inFormat.italic, aaType==aaAdvancedLcd); } } // end namespace nme diff --git a/samples/02-Text/Sample.hx b/samples/02-Text/Sample.hx index 6abe5cd06..92713a384 100644 --- a/samples/02-Text/Sample.hx +++ b/samples/02-Text/Sample.hx @@ -15,6 +15,9 @@ class Sample extends Sprite //var uiScale = nme.ui.Scale.getFontScale(); //scaleX = scaleY = uiScale; + TextField.defaultAntiAliasType = stage.hasHardwareLcdFonts ? + AntiAliasType.ADVANCED_LCD : AntiAliasType.ADVANCED; + for(side in 0...2) { var col = (0xFF + side * 0xFF ) % 0xffffff; @@ -83,23 +86,34 @@ class Sample extends Sprite var aaText = ["normal","advanced","advanced_lcd"]; var cabText = ["software","hardware"]; - for(cab in 0...2) - for(aa in 0...3) - { - var tf = new nme.text.TextField(); - tf.autoSize = TextFieldAutoSize.LEFT; - tf.background = true; - tf.backgroundColor = 0xe0e0e0; - tf.border = true; - tf.borderColor = 0x000000; - tf.antiAliasType = aa; - tf.text = "Utf1 Lorem Ipsum " + cabText[cab] + " " + aaText[aa]; - tf.cacheAsBitmap = cab==1; - - addChild(tf); - tf.x = 20; - tf.y = 350 + aa*24 + cab*24*3; - } + + var tf = new nme.text.TextField(); + tf.autoSize = TextFieldAutoSize.LEFT; + tf.y = 330; + tf.x = 20; + tf.htmlText = "stage.hasHardwareLcdFonts " + stage.hasHardwareLcdFonts+ ""; + tf.antiAliasType = AntiAliasType.ADVANCED_LCD; + addChild(tf); + + for(side in 0...2) + for(cab in 0...2) + for(aa in 0...3) + { + var tf = new nme.text.TextField(); + tf.autoSize = TextFieldAutoSize.LEFT; + tf.background = true; + tf.backgroundColor = side==0 ? 0xe0e0e0 : 0x202020; + tf.border = true; + tf.borderColor = side==0 ? 0x000000 : 0x0000ff; + tf.antiAliasType = aa; + tf.textColor = side==0 ? 0x000000 : 0xffffff; + tf.text = "Utf1 Lorem Ipsum " + cabText[cab] + " " + aaText[aa]; + tf.cacheAsBitmap = cab==0; + + addChild(tf); + tf.x = 20 + side*300; + tf.y = 360 + aa*24 + cab*24*3; + } } } diff --git a/src/nme/app/Window.hx b/src/nme/app/Window.hx index 364134326..ab38ca68c 100644 --- a/src/nme/app/Window.hx +++ b/src/nme/app/Window.hx @@ -19,6 +19,7 @@ class Window public var displayState(get, set):StageDisplayState; public var dpiScale(get, null):Float; public var isOpenGL(get, null):Bool; + public var hasHardwareLcdFonts(get, null):Bool; public var quality(get, set):StageQuality; public var scaleMode(get, set):StageScaleMode; public var globalMouseState(get, never):MouseState; @@ -387,6 +388,12 @@ class Window return nme_stage_is_opengl(nmeStageHandle); } + public function get_hasHardwareLcdFonts():Bool + { + return nme_stage_has_hardware_lcd_fonts(nmeStageHandle); + } + + public function get_quality():StageQuality { var i:Int = nme_stage_get_quality(nmeStageHandle); @@ -460,6 +467,7 @@ class Window private static var nme_stage_resize_window = PrimeLoader.load("nme_stage_resize_window", "oiiv"); private static var nme_stage_is_opengl = PrimeLoader.load("nme_stage_is_opengl", "ob"); + private static var nme_stage_has_hardware_lcd_fonts = PrimeLoader.load("nme_stage_has_hardware_lcd_fonts", "ob"); private static var nme_stage_get_stage_width = PrimeLoader.load("nme_stage_get_stage_width", "oi"); private static var nme_stage_get_stage_height = PrimeLoader.load("nme_stage_get_stage_height", "oi"); private static var nme_stage_get_dpi_scale = PrimeLoader.load("nme_stage_get_dpi_scale", "od"); diff --git a/src/nme/display/Stage.hx b/src/nme/display/Stage.hx index 8f3ad6a7e..cd5581fbb 100644 --- a/src/nme/display/Stage.hx +++ b/src/nme/display/Stage.hx @@ -88,6 +88,7 @@ class Stage extends DisplayObjectContainer implements nme.app.IPollClient implem public var onQuit(get,set):Void -> Void; public var onCloseRequest:Void -> Void; public var isOpenGL(get, never):Bool; + public var hasHardwareLcdFonts(get, never):Bool; // Is this used? Could not tell where "event.down" is being set, therefore this would appear useless //public var onKey:Int -> Bool -> Int -> Int -> Void; @@ -1220,6 +1221,7 @@ class Stage extends DisplayObjectContainer implements nme.app.IPollClient implem private function get_stageHeight():Int return window.height; private function get_stageWidth():Int return window.width; private function get_isOpenGL():Bool return window.get_isOpenGL(); + private function get_hasHardwareLcdFonts():Bool return window.get_hasHardwareLcdFonts(); private function get_renderRequest():Void->Bool return window.renderRequest; private function set_renderRequest(f:Void->Bool):Void->Bool return window.renderRequest = f;