<commit_before>/*************************************************************************
 *
 *  $RCSfile: scriptinfo.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2004-04-27 13:42:22 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _SCRIPTINFO_HXX
#define _SCRIPTINFO_HXX

#ifndef _SVSTDARR_HXX
#define _SVSTDARR_SHORTS
#define _SVSTDARR_BYTES
#define _SVSTDARR_USHORTS
#define _SVSTDARR_XUB_STRLEN
#include <svtools/svstdarr.hxx>
#endif

#ifndef _LANG_HXX
#include <tools/lang.hxx>
#endif
#include <list>

class SwWrongList;
class SwTxtNode;
class Point;
class MultiSelection;
typedef std::list< xub_StrLen > PositionList;

/*************************************************************************
 *                class SwScanner
 * Hilfsklasse, die beim Spellen die Worte im gewuenschten Bereich
 * nacheinander zur Verfuegung stellt.
 *************************************************************************/

class SwScanner
{
    XubString aWord;
    const SwWrongList* pWrong;
    const SwTxtNode& rNode;
    xub_StrLen nEndPos;
    xub_StrLen nBegin;
    xub_StrLen nLen;
    LanguageType aCurrLang;
    USHORT nWordType;
    BOOL bReverse;
    BOOL bStart;
    BOOL bIsOnlineSpell;

public:
    SwScanner( const SwTxtNode& rNd, const SwWrongList* pWrng, USHORT nWordType,
               xub_StrLen nStart, xub_StrLen nEnde, BOOL bRev, BOOL bOS );

    // This next word function tries to find the language for the next word
    // It should currently _not_ be used for spell checking, and works only for
    // ! bReverse
    BOOL NextWord();
    BOOL NextWord( LanguageType aLang );

    const XubString& GetWord() const    { return aWord; }

    xub_StrLen GetBegin() const         { return nBegin; }
    xub_StrLen GetEnd() const           { return nBegin + nLen; }
    xub_StrLen GetLen() const           { return nLen; }
};

/*************************************************************************
 *                      class SwScriptInfo
 *
 * encapsultes information about script changes
 *************************************************************************/

class SwScriptInfo
{
private:
    SvXub_StrLens aScriptChg;
    SvBytes aScriptType;
    SvXub_StrLens aDirChg;
    SvBytes aDirType;
    SvXub_StrLens aKashida;
    SvXub_StrLens aCompChg;
    SvXub_StrLens aCompLen;
    SvXub_StrLens aHiddenChg;
    SvBytes aCompType;
    xub_StrLen nInvalidityPos;
    BYTE nDefaultDir;

    void UpdateBidiInfo( const String& rTxt );

public:
    enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE };

    inline SwScriptInfo() : nInvalidityPos( 0 ), nDefaultDir( 0 ) {};

    // determines script changes
    void InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL );
    void InitScriptInfo( const SwTxtNode& rNode );

    // set/get position from which data is invalid
    inline void SetInvalidity( const xub_StrLen nPos );
    inline xub_StrLen GetInvalidity() const { return nInvalidityPos; };

    // get default direction for paragraph
    inline BYTE GetDefaultDir() const { return nDefaultDir; };

    // array operations, nCnt refers to array position
    inline USHORT CountScriptChg() const;
    inline xub_StrLen GetScriptChg( const USHORT nCnt ) const;
    inline BYTE GetScriptType( const USHORT nCnt ) const;

    inline USHORT CountDirChg() const;
    inline xub_StrLen GetDirChg( const USHORT nCnt ) const;
    inline BYTE GetDirType( const USHORT nCnt ) const;

    inline USHORT CountKashida() const;
    inline xub_StrLen GetKashida( const USHORT nCnt ) const;

    inline USHORT CountCompChg() const;
    inline xub_StrLen GetCompStart( const USHORT nCnt ) const;
    inline xub_StrLen GetCompLen( const USHORT nCnt ) const;
    inline BYTE GetCompType( const USHORT nCnt ) const;

    inline USHORT CountHiddenChg() const;
    inline xub_StrLen GetHiddenChg( const USHORT nCnt ) const;
    static void SwScriptInfo::CalcHiddenRanges( const SwTxtNode& rNode,
                                                MultiSelection& rHiddenMulti );

    // "high" level operations, nPos refers to string position
    xub_StrLen NextScriptChg( const xub_StrLen nPos ) const;
    BYTE ScriptType( const xub_StrLen nPos ) const;

    // Returns the position of the next direction level change.
    // If bLevel is set, the position of the next level which is smaller
    // than the level at position nPos is returned. This is required to
    // obtain the end of a SwBidiPortion
    xub_StrLen NextDirChg( const xub_StrLen nPos,
                           const BYTE* pLevel = 0 ) const;
    BYTE DirType( const xub_StrLen nPos ) const;

    BYTE CompType( const xub_StrLen nPos ) const;

/** Hidden text range information - static and non-version

    @descr  Determines if a given position is inside a hidden text range. The
            static version tries to obtain a valid SwScriptInfo object
            via the SwTxtNode, otherwise it calculates the values from scratch.
            The non-static version uses the internally cached informatio
            for the calculation.

    @param  rNode
                The text node.
    @param  nPos
                The given position that should be checked.
    @param  rnStartPos
                Return parameter for the start position of the hidden range.
                STRING_LEN if nPos is not inside a hidden range.
    @param  rnEndPos
                Return parameter for the end position of the hidden range.
                0 if nPos is not inside a hidden range.
    @param  rnEndPos
                Return parameter that contains all the hidden text ranges. Optional.
    @return
            returns true if there are any hidden characters in this paragraph.

*/
    static bool GetBoundsOfHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos,
                                        xub_StrLen& rnStartPos, xub_StrLen& rnEndPos,
                                        PositionList* pList = 0 );
    bool GetBoundsOfHiddenRange(  xub_StrLen nPos, xub_StrLen& rnStartPos,
                                  xub_StrLen& rnEndPos, PositionList* pList = 0 ) const;

    static bool IsInHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos );

/** Hidden text range information

    @descr  Takes a string and either deletes the hidden ranges or sets
            a given character in place of the hidden characters.

    @param  rNode
                The text node.
    @param  nPos
                The string to modify.
    @param  cChar
                The character that should replace the hidden characters.
 */
    static USHORT MaskHiddenRanges( const SwTxtNode& rNode, XubString& rText,
                                    const xub_StrLen nStt, const xub_StrLen nEnd,
                                    const xub_Unicode cChar );

    // examines the range [ nStart, nStart + nEnd ] if there are kanas
    // returns start index of kana entry in array, otherwise USHRT_MAX
    USHORT HasKana( xub_StrLen nStart, const xub_StrLen nEnd ) const;

    // modifies the kerning array according to a given compress value
    long Compress( long* pKernArray, xub_StrLen nIdx, xub_StrLen nLen,
                   const USHORT nCompress, const USHORT nFontHeight,
                   Point* pPoint = NULL ) const;

/** Performes a kashida justification on the kerning array

    @descr  Add some extra space for kashida justification to the
            positions in the kerning array.
    @param  pKernArray
                The printers kerning array. Optional.
    @param  pScrArray
                The screen kerning array. Optional.
    @param  nIdx
                Start referring to the paragraph.
    @param  nLen
                The number of characters to be considered.
    @param  nSpace
                The value which has to be added to a kashida opportunity.
    @return The number of kashida opportunities in the given range
*/
    USHORT KashidaJustify( long* pKernArray ,long* pScrArray,
                           xub_StrLen nIdx, xub_StrLen nLen,
                           USHORT nSpace = 0 ) const;

/** Checks if language is one of the 16 Arabic languages

    @descr  Checks if language is one of the 16 Arabic languages
    @param  aLang
                The language which has to be checked.
    @return Returns if the language is an Arabic language
*/
    static BOOL IsArabicLanguage( LanguageType aLang );

/** Performes a thai justification on the kerning array

    @descr  Add some extra space for thai justification to the
            positions in the kerning array.
    @param  rTxt
                The String
    @param  pKernArray
                The printers kerning array. Optional.
    @param  pScrArray
                The screen kerning array. Optional.
    @param  nIdx
                Start referring to the paragraph.
    @param  nLen
                The number of characters to be considered.
    @param  nSpace
                The value which has to be added to the cells.
    @return The number of extra spaces in the given range
*/
    static USHORT ThaiJustify( const XubString& rTxt, long* pKernArray,
                               long* pScrArray, xub_StrLen nIdx,
                               xub_StrLen nLen, USHORT nSpace = 0 );

    static SwScriptInfo* GetScriptInfo( const SwTxtNode& rNode,
                                        sal_Bool bAllowInvalid = sal_False );

    static BYTE WhichFont( xub_StrLen nIdx, const String* pTxt, const SwScriptInfo* pSI );
};

inline void SwScriptInfo::SetInvalidity( const xub_StrLen nPos )
{
    if ( nPos < nInvalidityPos )
        nInvalidityPos = nPos;
};
inline USHORT SwScriptInfo::CountScriptChg() const { return aScriptChg.Count(); }
inline xub_StrLen SwScriptInfo::GetScriptChg( const USHORT nCnt ) const
{
    ASSERT( nCnt < aScriptChg.Count(),"No ScriptChange today!");
    return aScriptChg[ nCnt ];
}
inline BYTE SwScriptInfo::GetScriptType( const xub_StrLen nCnt ) const
{
    ASSERT( nCnt < aScriptChg.Count(),"No ScriptType today!");
    return aScriptType[ nCnt ];
}

inline USHORT SwScriptInfo::CountDirChg() const { return aDirChg.Count(); }
inline xub_StrLen SwScriptInfo::GetDirChg( const USHORT nCnt ) const
{
    ASSERT( nCnt < aDirChg.Count(),"No DirChange today!");
    return aDirChg[ nCnt ];
}
inline BYTE SwScriptInfo::GetDirType( const xub_StrLen nCnt ) const
{
    ASSERT( nCnt < aDirChg.Count(),"No DirType today!");
    return aDirType[ nCnt ];
}

inline USHORT SwScriptInfo::CountKashida() const { return aKashida.Count(); }
inline xub_StrLen SwScriptInfo::GetKashida( const USHORT nCnt ) const
{
    ASSERT( nCnt < aKashida.Count(),"No Kashidas today!");
    return aKashida[ nCnt ];
}

inline USHORT SwScriptInfo::CountCompChg() const { return aCompChg.Count(); };
inline xub_StrLen SwScriptInfo::GetCompStart( const USHORT nCnt ) const
{
    ASSERT( nCnt < aCompChg.Count(),"No CompressionStart today!");
    return aCompChg[ nCnt ];
}
inline xub_StrLen SwScriptInfo::GetCompLen( const USHORT nCnt ) const
{
    ASSERT( nCnt < aCompChg.Count(),"No CompressionLen today!");
    return aCompLen[ nCnt ];
}

inline BYTE SwScriptInfo::GetCompType( const USHORT nCnt ) const
{
    ASSERT( nCnt < aCompChg.Count(),"No CompressionType today!");
    return aCompType[ nCnt ];
}

inline USHORT SwScriptInfo::CountHiddenChg() const { return aHiddenChg.Count(); };
inline xub_StrLen SwScriptInfo::GetHiddenChg( const USHORT nCnt ) const
{
    ASSERT( nCnt < aHiddenChg.Count(),"No HiddenChg today!");
    return aHiddenChg[ nCnt ];
}

#endif
<commit_msg>INTEGRATION: CWS swqbugfixes02 (1.4.58); FILE MERGED 2004/06/09 07:06:15 fme 1.4.58.1: #i29968# Remove hidden text ranges from document before sending it<commit_after>/*************************************************************************
 *
 *  $RCSfile: scriptinfo.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: kz $ $Date: 2004-06-29 08:08:37 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _SCRIPTINFO_HXX
#define _SCRIPTINFO_HXX

#ifndef _SVSTDARR_HXX
#define _SVSTDARR_SHORTS
#define _SVSTDARR_BYTES
#define _SVSTDARR_USHORTS
#define _SVSTDARR_XUB_STRLEN
#include <svtools/svstdarr.hxx>
#endif

#ifndef _LANG_HXX
#include <tools/lang.hxx>
#endif
#include <list>

class SwWrongList;
class SwTxtNode;
class Point;
class MultiSelection;
typedef std::list< xub_StrLen > PositionList;

/*************************************************************************
 *                class SwScanner
 * Hilfsklasse, die beim Spellen die Worte im gewuenschten Bereich
 * nacheinander zur Verfuegung stellt.
 *************************************************************************/

class SwScanner
{
    XubString aWord;
    const SwWrongList* pWrong;
    const SwTxtNode& rNode;
    xub_StrLen nEndPos;
    xub_StrLen nBegin;
    xub_StrLen nLen;
    LanguageType aCurrLang;
    USHORT nWordType;
    BOOL bReverse;
    BOOL bStart;
    BOOL bIsOnlineSpell;

public:
    SwScanner( const SwTxtNode& rNd, const SwWrongList* pWrng, USHORT nWordType,
               xub_StrLen nStart, xub_StrLen nEnde, BOOL bRev, BOOL bOS );

    // This next word function tries to find the language for the next word
    // It should currently _not_ be used for spell checking, and works only for
    // ! bReverse
    BOOL NextWord();
    BOOL NextWord( LanguageType aLang );

    const XubString& GetWord() const    { return aWord; }

    xub_StrLen GetBegin() const         { return nBegin; }
    xub_StrLen GetEnd() const           { return nBegin + nLen; }
    xub_StrLen GetLen() const           { return nLen; }
};

/*************************************************************************
 *                      class SwScriptInfo
 *
 * encapsultes information about script changes
 *************************************************************************/

class SwScriptInfo
{
private:
    SvXub_StrLens aScriptChg;
    SvBytes aScriptType;
    SvXub_StrLens aDirChg;
    SvBytes aDirType;
    SvXub_StrLens aKashida;
    SvXub_StrLens aCompChg;
    SvXub_StrLens aCompLen;
    SvXub_StrLens aHiddenChg;
    SvBytes aCompType;
    xub_StrLen nInvalidityPos;
    BYTE nDefaultDir;

    void UpdateBidiInfo( const String& rTxt );

public:
    enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE };

    inline SwScriptInfo() : nInvalidityPos( 0 ), nDefaultDir( 0 ) {};

    // determines script changes
    void InitScriptInfo( const SwTxtNode& rNode, sal_Bool bRTL );
    void InitScriptInfo( const SwTxtNode& rNode );

    // set/get position from which data is invalid
    inline void SetInvalidity( const xub_StrLen nPos );
    inline xub_StrLen GetInvalidity() const { return nInvalidityPos; };

    // get default direction for paragraph
    inline BYTE GetDefaultDir() const { return nDefaultDir; };

    // array operations, nCnt refers to array position
    inline USHORT CountScriptChg() const;
    inline xub_StrLen GetScriptChg( const USHORT nCnt ) const;
    inline BYTE GetScriptType( const USHORT nCnt ) const;

    inline USHORT CountDirChg() const;
    inline xub_StrLen GetDirChg( const USHORT nCnt ) const;
    inline BYTE GetDirType( const USHORT nCnt ) const;

    inline USHORT CountKashida() const;
    inline xub_StrLen GetKashida( const USHORT nCnt ) const;

    inline USHORT CountCompChg() const;
    inline xub_StrLen GetCompStart( const USHORT nCnt ) const;
    inline xub_StrLen GetCompLen( const USHORT nCnt ) const;
    inline BYTE GetCompType( const USHORT nCnt ) const;

    inline USHORT CountHiddenChg() const;
    inline xub_StrLen GetHiddenChg( const USHORT nCnt ) const;
    static void SwScriptInfo::CalcHiddenRanges( const SwTxtNode& rNode,
                                                MultiSelection& rHiddenMulti );

    // "high" level operations, nPos refers to string position
    xub_StrLen NextScriptChg( const xub_StrLen nPos ) const;
    BYTE ScriptType( const xub_StrLen nPos ) const;

    // Returns the position of the next direction level change.
    // If bLevel is set, the position of the next level which is smaller
    // than the level at position nPos is returned. This is required to
    // obtain the end of a SwBidiPortion
    xub_StrLen NextDirChg( const xub_StrLen nPos,
                           const BYTE* pLevel = 0 ) const;
    BYTE DirType( const xub_StrLen nPos ) const;

    BYTE CompType( const xub_StrLen nPos ) const;

    //
    // HIDDEN TEXT STUFF START
    //

/** Hidden text range information - static and non-version

    @descr  Determines if a given position is inside a hidden text range. The
            static version tries to obtain a valid SwScriptInfo object
            via the SwTxtNode, otherwise it calculates the values from scratch.
            The non-static version uses the internally cached informatio
            for the calculation.

    @param  rNode
                The text node.
    @param  nPos
                The given position that should be checked.
    @param  rnStartPos
                Return parameter for the start position of the hidden range.
                STRING_LEN if nPos is not inside a hidden range.
    @param  rnEndPos
                Return parameter for the end position of the hidden range.
                0 if nPos is not inside a hidden range.
    @param  rnEndPos
                Return parameter that contains all the hidden text ranges. Optional.
    @return
            returns true if there are any hidden characters in this paragraph.

*/
    static bool GetBoundsOfHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos,
                                        xub_StrLen& rnStartPos, xub_StrLen& rnEndPos,
                                        PositionList* pList = 0 );
    bool GetBoundsOfHiddenRange(  xub_StrLen nPos, xub_StrLen& rnStartPos,
                                  xub_StrLen& rnEndPos, PositionList* pList = 0 ) const;

    static bool IsInHiddenRange( const SwTxtNode& rNode, xub_StrLen nPos );

/** Hidden text attribute handling

    @descr  Takes a string and either deletes the hidden ranges or sets
            a given character in place of the hidden characters.

    @param  rNode
                The text node.
    @param  nPos
                The string to modify.
    @param  cChar
                The character that should replace the hidden characters.
    @param  bDel
                If set, the hidden ranges will be deleted from the text node.
 */
    static USHORT MaskHiddenRanges( const SwTxtNode& rNode, XubString& rText,
                                    const xub_StrLen nStt, const xub_StrLen nEnd,
                                    const xub_Unicode cChar );

/** Hidden text attribute handling

    @descr  Takes a SwTxtNode and deletes the hidden ranges from the node.

    @param  rNode
                The text node.
 */
    static void DeleteHiddenRanges( SwTxtNode& rNode );

    //
    // HIDDEN TEXT STUFF END
    //

    // examines the range [ nStart, nStart + nEnd ] if there are kanas
    // returns start index of kana entry in array, otherwise USHRT_MAX
    USHORT HasKana( xub_StrLen nStart, const xub_StrLen nEnd ) const;

    // modifies the kerning array according to a given compress value
    long Compress( long* pKernArray, xub_StrLen nIdx, xub_StrLen nLen,
                   const USHORT nCompress, const USHORT nFontHeight,
                   Point* pPoint = NULL ) const;

/** Performes a kashida justification on the kerning array

    @descr  Add some extra space for kashida justification to the
            positions in the kerning array.
    @param  pKernArray
                The printers kerning array. Optional.
    @param  pScrArray
                The screen kerning array. Optional.
    @param  nIdx
                Start referring to the paragraph.
    @param  nLen
                The number of characters to be considered.
    @param  nSpace
                The value which has to be added to a kashida opportunity.
    @return The number of kashida opportunities in the given range
*/
    USHORT KashidaJustify( long* pKernArray ,long* pScrArray,
                           xub_StrLen nIdx, xub_StrLen nLen,
                           USHORT nSpace = 0 ) const;

/** Checks if language is one of the 16 Arabic languages

    @descr  Checks if language is one of the 16 Arabic languages
    @param  aLang
                The language which has to be checked.
    @return Returns if the language is an Arabic language
*/
    static BOOL IsArabicLanguage( LanguageType aLang );

/** Performes a thai justification on the kerning array

    @descr  Add some extra space for thai justification to the
            positions in the kerning array.
    @param  rTxt
                The String
    @param  pKernArray
                The printers kerning array. Optional.
    @param  pScrArray
                The screen kerning array. Optional.
    @param  nIdx
                Start referring to the paragraph.
    @param  nLen
                The number of characters to be considered.
    @param  nSpace
                The value which has to be added to the cells.
    @return The number of extra spaces in the given range
*/
    static USHORT ThaiJustify( const XubString& rTxt, long* pKernArray,
                               long* pScrArray, xub_StrLen nIdx,
                               xub_StrLen nLen, USHORT nSpace = 0 );

    static SwScriptInfo* GetScriptInfo( const SwTxtNode& rNode,
                                        sal_Bool bAllowInvalid = sal_False );

    static BYTE WhichFont( xub_StrLen nIdx, const String* pTxt, const SwScriptInfo* pSI );
};

inline void SwScriptInfo::SetInvalidity( const xub_StrLen nPos )
{
    if ( nPos < nInvalidityPos )
        nInvalidityPos = nPos;
};
inline USHORT SwScriptInfo::CountScriptChg() const { return aScriptChg.Count(); }
inline xub_StrLen SwScriptInfo::GetScriptChg( const USHORT nCnt ) const
{
    ASSERT( nCnt < aScriptChg.Count(),"No ScriptChange today!");
    return aScriptChg[ nCnt ];
}
inline BYTE SwScriptInfo::GetScriptType( const xub_StrLen nCnt ) const
{
    ASSERT( nCnt < aScriptChg.Count(),"No ScriptType today!");
    return aScriptType[ nCnt ];
}

inline USHORT SwScriptInfo::CountDirChg() const { return aDirChg.Count(); }
inline xub_StrLen SwScriptInfo::GetDirChg( const USHORT nCnt ) const
{
    ASSERT( nCnt < aDirChg.Count(),"No DirChange today!");
    return aDirChg[ nCnt ];
}
inline BYTE SwScriptInfo::GetDirType( const xub_StrLen nCnt ) const
{
    ASSERT( nCnt < aDirChg.Count(),"No DirType today!");
    return aDirType[ nCnt ];
}

inline USHORT SwScriptInfo::CountKashida() const { return aKashida.Count(); }
inline xub_StrLen SwScriptInfo::GetKashida( const USHORT nCnt ) const
{
    ASSERT( nCnt < aKashida.Count(),"No Kashidas today!");
    return aKashida[ nCnt ];
}

inline USHORT SwScriptInfo::CountCompChg() const { return aCompChg.Count(); };
inline xub_StrLen SwScriptInfo::GetCompStart( const USHORT nCnt ) const
{
    ASSERT( nCnt < aCompChg.Count(),"No CompressionStart today!");
    return aCompChg[ nCnt ];
}
inline xub_StrLen SwScriptInfo::GetCompLen( const USHORT nCnt ) const
{
    ASSERT( nCnt < aCompChg.Count(),"No CompressionLen today!");
    return aCompLen[ nCnt ];
}

inline BYTE SwScriptInfo::GetCompType( const USHORT nCnt ) const
{
    ASSERT( nCnt < aCompChg.Count(),"No CompressionType today!");
    return aCompType[ nCnt ];
}

inline USHORT SwScriptInfo::CountHiddenChg() const { return aHiddenChg.Count(); };
inline xub_StrLen SwScriptInfo::GetHiddenChg( const USHORT nCnt ) const
{
    ASSERT( nCnt < aHiddenChg.Count(),"No HiddenChg today!");
    return aHiddenChg[ nCnt ];
}

#endif
<|endoftext|>


<commit_before>#include "PolyStatic.hpp"

#include <string>
#include <map>
#include <fstream>

namespace ps
{
	namespace
	{
		struct ParseElement
		{
			virtual ParseElement *Clone() const = 0;
			virtual ~ParseElement(){}
		};
		struct ScriptFile : public virtual ParseElement
		{
			std::string filename;
			ScriptFile(std::string const&filename) : filename(filename) {}
			virtual ScriptFile *Clone() const
			{
				return new ScriptFile(*this);
			}
			virtual ~ScriptFile(){}
		};
		struct Script : public virtual ParseElement
		{
			std::string script;
			Script(std::string const &script) : script(script) {}
			virtual Script *Clone() const
			{
				return new Script(*this);
			}
			virtual ~Script(){}
		};
	}
	struct Parser::Impl
	{
		using elems_t = std::map<std::string, ParseElement *>;
		elems_t elems;
		ErrorHandler eh;

		Impl() : eh([](Parser &, Error const &, bool w) -> bool { return w; })
		{
		}
		Impl(Impl const &impl) : eh(impl.eh)
		{
			for(elems_t::const_iterator it = impl.elems.begin(); it != impl.elems.end(); ++it)
			{
				elems[it->first] = it->second->Clone();
			}
		}
		~Impl()
		{
			for(elems_t::iterator it = elems.begin(); it != elems.end(); ++it)
			{
				delete it->second;
			}
		}
	};
	Parser::Parser() : impl(new Impl)
	{
	}
	Parser::Parser(char const *script) : impl(new Impl)
	{
		impl->elems[""] = new Script(script);
	}
	Parser::Parser(Parser const &parser) : impl(new Impl(*parser.impl))
	{
	}
	Parser::~Parser()
	{
		delete impl;
		impl = 0;
	}

	void Parser::AddScriptFile(char const *scriptfilename)
	{
		RemoveScript(scriptfilename);
		impl->elems[scriptfilename] = new ScriptFile(scriptfilename);
	}
	void Parser::AddScript(char const *scriptname, char const *contents)
	{
		RemoveScript(scriptname);
		impl->elems[scriptname] = new Script(contents);
	}
	void Parser::RemoveScript(char const *scriptname)
	{
		Impl::elems_t e (impl->elems);
		if(e.find(scriptname) != e.end())
		{
			delete e[scriptname];
			e.erase(scriptname);
		}
	}

	void Parser::SetErrorHandler(ErrorHandler &eh)
	{
		impl->eh = &eh;
	}
	struct Parser::Error::Impl
	{
		std::string msg, script;
		unsigned lns, lne, cns, cne;
	};
	Parser::Error::Error() : impl(new Impl)
	{
	}
	Parser::Error::~Error()
	{
		delete impl;
		impl = 0;
	}
	char const *Parser::Error::ErrorString() const
	{
		return impl->msg.c_str();
	}
	char const *Parser::Error::ScriptName() const
	{
		return impl->script.c_str();
	}
	unsigned Parser::Error::LineNumberStart() const
	{
		return impl->lns;
	}
	unsigned Parser::Error::LineNumberEnd() const
	{
		return impl->lne;
	}
	unsigned Parser::Error::ColumnNumberStart() const
	{
		return impl->cns;
	}
	unsigned Parser::Error::ColumnNumberEnd() const
	{
		return impl->cne;
	}

	bool Parser::Parse()
	{
		return false;
	}
}
<commit_msg>Fix deleting unique_ptr<commit_after>#include "PolyStatic.hpp"

#include <string>
#include <map>
#include <fstream>

namespace ps
{
	namespace
	{
		struct ParseElement
		{
			virtual ParseElement *Clone() const = 0;
			virtual ~ParseElement(){}
		};
		struct ScriptFile : public virtual ParseElement
		{
			std::string filename;
			ScriptFile(std::string const&filename) : filename(filename) {}
			virtual ScriptFile *Clone() const
			{
				return new ScriptFile(*this);
			}
			virtual ~ScriptFile(){}
		};
		struct Script : public virtual ParseElement
		{
			std::string script;
			Script(std::string const &script) : script(script) {}
			virtual Script *Clone() const
			{
				return new Script(*this);
			}
			virtual ~Script(){}
		};
	}
	struct Parser::Impl
	{
		using elems_t = std::map<std::string, ParseElement *>;
		elems_t elems;
		ErrorHandler eh;

		Impl() : eh([](Parser &, Error const &, bool w) -> bool { return w; })
		{
		}
		Impl(Impl const &impl) : eh(impl.eh)
		{
			for(elems_t::const_iterator it = impl.elems.begin(); it != impl.elems.end(); ++it)
			{
				elems[it->first] = it->second->Clone();
			}
		}
		~Impl()
		{
			for(elems_t::iterator it = elems.begin(); it != elems.end(); ++it)
			{
				delete it->second;
			}
		}
	};
	Parser::Parser() : impl(new Impl)
	{
	}
	Parser::Parser(char const *script) : impl(new Impl)
	{
		impl->elems[""] = new Script(script);
	}
	Parser::Parser(Parser const &parser) : impl(new Impl(*parser.impl))
	{
	}
	Parser::~Parser()
	{
	}

	void Parser::AddScriptFile(char const *scriptfilename)
	{
		RemoveScript(scriptfilename);
		impl->elems[scriptfilename] = new ScriptFile(scriptfilename);
	}
	void Parser::AddScript(char const *scriptname, char const *contents)
	{
		RemoveScript(scriptname);
		impl->elems[scriptname] = new Script(contents);
	}
	void Parser::RemoveScript(char const *scriptname)
	{
		Impl::elems_t e (impl->elems);
		if(e.find(scriptname) != e.end())
		{
			delete e[scriptname];
			e.erase(scriptname);
		}
	}

	void Parser::SetErrorHandler(ErrorHandler &eh)
	{
		impl->eh = &eh;
	}
	struct Parser::Error::Impl
	{
		std::string msg, script;
		unsigned lns, lne, cns, cne;
	};
	Parser::Error::Error() : impl(new Impl)
	{
	}
	Parser::Error::~Error()
	{
	}
	char const *Parser::Error::ErrorString() const
	{
		return impl->msg.c_str();
	}
	char const *Parser::Error::ScriptName() const
	{
		return impl->script.c_str();
	}
	unsigned Parser::Error::LineNumberStart() const
	{
		return impl->lns;
	}
	unsigned Parser::Error::LineNumberEnd() const
	{
		return impl->lne;
	}
	unsigned Parser::Error::ColumnNumberStart() const
	{
		return impl->cns;
	}
	unsigned Parser::Error::ColumnNumberEnd() const
	{
		return impl->cne;
	}

	bool Parser::Parse()
	{
		return false;
	}
}
<|endoftext|>


<commit_before>#include <OpenGLTexture.h>

#include <TextureRef.h>
#include <Image.h>
#include <Surface.h>

#define GL_GLEXT_PROTOTYPES

#if defined __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#elif (defined GL_ES)
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#else
#define GL_GLEXT_PROTOTYPES

#ifdef _WIN32
#include <GL/glew.h>
#include <windows.h>
#endif

#ifdef __ANDROID__
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#else
#include <GL/gl.h>

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif
#endif

#endif

#if defined __APPLE__ || defined __ANDROID__
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0
#endif
#ifndef GL_COMPRESSED_RED_RGTC1
#define GL_COMPRESSED_RED_RGTC1 0x8DBB
#endif
#ifndef GL_COMPRESSED_RG_RGTC2
#define GL_COMPRESSED_RG_RGTC2 0x8DBD
#endif
#endif

#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;
bool OpenGLTexture::global_init = false;
bool OpenGLTexture::has_tex_storage = false;

struct format_description_s {
  GLenum internalFormat;
  GLenum format;
  GLenum type;
};

OpenGLTexture::OpenGLTexture(Surface & surface)
  : Texture(surface.getLogicalWidth(), surface.getLogicalHeight(), surface.getActualWidth(), surface.getActualHeight(), surface.getMinFilter(), surface.getMagFilter(), surface.getTargetFormat(), 1) {
  assert(getInternalFormat());
  assert(getLogicalWidth() > 0);
  assert(getLogicalHeight() > 0);
  assert(getActualWidth() > 0);
  assert(getActualHeight() > 0);
  auto image = surface.createImage();
  updateData(*image, 0, 0);
}

static format_description_s getFormatDescription(InternalFormat internal_format) {
  switch (internal_format) {
  case NO_FORMAT: return { 0, 0, 0 };
  case R8: return { GL_R8, GL_RED, GL_UNSIGNED_BYTE };
  case RG8: return { GL_RG8, GL_RG, GL_UNSIGNED_BYTE };
  case RGB565: return { GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 };
  case RGBA4: return { GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 };
  case RGBA8:
#if defined __APPLE__ || defined __ANDROID__
    return { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
#elif defined _WIN32
    return { GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV };
#else
    // Linux (doesn't work for OpenGL ES)
    return { GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV };
#endif
  case RGB8:
#if defined __APPLE__ || defined __ANDROID__
    return { GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE };
#elif defined _WIN32
    return { GL_RGB8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV };
#else
    // Linux
    return { GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV };
#endif
    // case RGB8_24: return GL_RGBA8;
  case RED_RGTC1: return { GL_COMPRESSED_RED_RGTC1, GL_RG, 0 };
  case RG_RGTC2: return { GL_COMPRESSED_RG_RGTC2, GL_RG, 0 };
  case RGB_ETC1: return { GL_COMPRESSED_RGB8_ETC2, GL_RGB, 0 };
  case RGB_DXT1: return { GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, 0 };
  case RGBA_DXT5: return { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, 0 };
  case LUMINANCE_ALPHA: return { GL_RG8, GL_RG, GL_UNSIGNED_BYTE };
  case LA44: // pack luminance and alpha to single byte
    return { GL_R8, GL_RED, GL_UNSIGNED_BYTE };
  case R32F: return { GL_R32F, GL_RED, GL_FLOAT };
  default:
    break;
  }
  cerr << "unhandled format: " << int(internal_format) << endl;
  assert(0);
  return { 0, 0, 0 };
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateTextureData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  auto fd = getFormatDescription(getInternalFormat());
  bool filled = false;

  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    cerr << "plain tex: f = " << int(getInternalFormat()) << ", x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", size = " << size << ", offset = " << offset << endl;
    assert(image.getData());

    if (fd.type == 0) { // compressed
      if (hasTexStorage() || is_data_initialized) {
	glCompressedTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, fd.internalFormat, (GLsizei)size, image.getData() + offset);
      } else {
	glCompressedTexImage2D(GL_TEXTURE_2D, level, fd.internalFormat, current_width, current_height, 0, (GLsizei)size, image.getData() + offset);
      }
    } else if (hasTexStorage() || is_data_initialized) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, fd.format, fd.type, image.getData() + offset);
    } else {
      glTexImage2D(GL_TEXTURE_2D, level, fd.internalFormat, current_width, current_height, 0, fd.format, fd.type, image.getData() + offset);
      filled = true;
    }

    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }

  if (filled) is_data_initialized = true;
}

void
OpenGLTexture::updateData(const Image & image, unsigned int x, unsigned int y) {
  if (!global_init) {
    global_init = true;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  }

  releaseTextures();

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    // cerr << "created texture id " << texture_id << " (total = " << total_textures << ")" << endl;
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    if (hasTexStorage()) {
      auto fd = getFormatDescription(getInternalFormat());
      glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, fd.internalFormat, getActualWidth(), getActualHeight());
    }
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));

    if (x != 0 || y != 0 || image.getWidth() != getActualWidth() || image.getHeight() != getActualHeight()) {
      int levels = has_mipmaps ? getMipmapLevels() : 1;
      Image img(getInternalFormat(), getActualWidth(), getActualHeight(), levels);
      updateTextureData(img, 0, 0);
    }
  }

  if (image.getInternalFormat() == getInternalFormat() ||
      (image.getInternalFormat() == RGB8 && getInternalFormat() == RGBA8)) {
    updateTextureData(image, x, y);
  } else {
    cerr << "OpenGLTexture: doing online image conversion from " << int(image.getInternalFormat()) << " to " << int(getInternalFormat()) << " (SLOW)\n";
    auto tmp_image = image.convert(getInternalFormat());
    updateTextureData(*tmp_image, x, y);
  }

  // if the image has only one level, and mipmaps are needed, generate them
  if (has_mipmaps && image.getLevels() == 1) {
    need_mipmaps = true;
  }
}

void
OpenGLTexture::generateMipmaps() {
  if (need_mipmaps) {
    if (getInternalFormat() != RGB_DXT1 && getInternalFormat() != RGB_ETC1 && getInternalFormat() != LA44 && getInternalFormat() != RED_RGTC1 && getInternalFormat() != RG_RGTC2) {
      glGenerateMipmap(GL_TEXTURE_2D);
    } else {
      cerr << "unable to generate mipmaps for compressed texture!\n";
    }
    need_mipmaps = false;
  }
}

void
OpenGLTexture::releaseTextures() {
  if (!freed_textures.empty()) {
    for (auto id : freed_textures) {
      cerr << "deleting texture " << id << endl;
      glDeleteTextures(1, &id);
    }
    freed_textures.clear();
  }
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  assert(_internal_format);
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}

TextureRef
OpenGLTexture::createTexture(Surface & surface) {
  return TextureRef( surface.getLogicalWidth(),
		     surface.getLogicalHeight(),
		     surface.getActualWidth(),
		     surface.getActualHeight(),
		     new OpenGLTexture(surface)
		     );
}
<commit_msg>disable debug prints<commit_after>#include <OpenGLTexture.h>

#include <TextureRef.h>
#include <Image.h>
#include <Surface.h>

#define GL_GLEXT_PROTOTYPES

#if defined __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#elif (defined GL_ES)
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#else
#define GL_GLEXT_PROTOTYPES

#ifdef _WIN32
#include <GL/glew.h>
#include <windows.h>
#endif

#ifdef __ANDROID__
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#else
#include <GL/gl.h>

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif
#endif

#endif

#if defined __APPLE__ || defined __ANDROID__
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0
#endif
#ifndef GL_COMPRESSED_RED_RGTC1
#define GL_COMPRESSED_RED_RGTC1 0x8DBB
#endif
#ifndef GL_COMPRESSED_RG_RGTC2
#define GL_COMPRESSED_RG_RGTC2 0x8DBD
#endif
#endif

#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;
bool OpenGLTexture::global_init = false;
bool OpenGLTexture::has_tex_storage = false;

struct format_description_s {
  GLenum internalFormat;
  GLenum format;
  GLenum type;
};

OpenGLTexture::OpenGLTexture(Surface & surface)
  : Texture(surface.getLogicalWidth(), surface.getLogicalHeight(), surface.getActualWidth(), surface.getActualHeight(), surface.getMinFilter(), surface.getMagFilter(), surface.getTargetFormat(), 1) {
  assert(getInternalFormat());
  assert(getLogicalWidth() > 0);
  assert(getLogicalHeight() > 0);
  assert(getActualWidth() > 0);
  assert(getActualHeight() > 0);
  auto image = surface.createImage();
  updateData(*image, 0, 0);
}

static format_description_s getFormatDescription(InternalFormat internal_format) {
  switch (internal_format) {
  case NO_FORMAT: return { 0, 0, 0 };
  case R8: return { GL_R8, GL_RED, GL_UNSIGNED_BYTE };
  case RG8: return { GL_RG8, GL_RG, GL_UNSIGNED_BYTE };
  case RGB565: return { GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 };
  case RGBA4: return { GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 };
  case RGBA8:
#if defined __APPLE__ || defined __ANDROID__
    return { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE };
#elif defined _WIN32
    return { GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV };
#else
    // Linux (doesn't work for OpenGL ES)
    return { GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV };
#endif
  case RGB8:
#if defined __APPLE__ || defined __ANDROID__
    return { GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE };
#elif defined _WIN32
    return { GL_RGB8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV };
#else
    // Linux
    return { GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV };
#endif
    // case RGB8_24: return GL_RGBA8;
  case RED_RGTC1: return { GL_COMPRESSED_RED_RGTC1, GL_RG, 0 };
  case RG_RGTC2: return { GL_COMPRESSED_RG_RGTC2, GL_RG, 0 };
  case RGB_ETC1: return { GL_COMPRESSED_RGB8_ETC2, GL_RGB, 0 };
  case RGB_DXT1: return { GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, 0 };
  case RGBA_DXT5: return { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, 0 };
  case LUMINANCE_ALPHA: return { GL_RG8, GL_RG, GL_UNSIGNED_BYTE };
  case LA44: // pack luminance and alpha to single byte
    return { GL_R8, GL_RED, GL_UNSIGNED_BYTE };
  case R32F: return { GL_R32F, GL_RED, GL_FLOAT };
  default:
    break;
  }
  cerr << "unhandled format: " << int(internal_format) << endl;
  assert(0);
  return { 0, 0, 0 };
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateTextureData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  auto fd = getFormatDescription(getInternalFormat());
  bool filled = false;

  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    // cerr << "plain tex: f = " << int(getInternalFormat()) << ", x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", size = " << size << ", offset = " << offset << endl;
    assert(image.getData());

    if (fd.type == 0) { // compressed
      if (hasTexStorage() || is_data_initialized) {
	glCompressedTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, fd.internalFormat, (GLsizei)size, image.getData() + offset);
      } else {
	glCompressedTexImage2D(GL_TEXTURE_2D, level, fd.internalFormat, current_width, current_height, 0, (GLsizei)size, image.getData() + offset);
      }
    } else if (hasTexStorage() || is_data_initialized) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, fd.format, fd.type, image.getData() + offset);
    } else {
      glTexImage2D(GL_TEXTURE_2D, level, fd.internalFormat, current_width, current_height, 0, fd.format, fd.type, image.getData() + offset);
      filled = true;
    }

    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }

  if (filled) is_data_initialized = true;
}

void
OpenGLTexture::updateData(const Image & image, unsigned int x, unsigned int y) {
  if (!global_init) {
    global_init = true;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  }

  releaseTextures();

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    // cerr << "created texture id " << texture_id << " (total = " << total_textures << ")" << endl;
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    if (hasTexStorage()) {
      auto fd = getFormatDescription(getInternalFormat());
      glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, fd.internalFormat, getActualWidth(), getActualHeight());
    }
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));

    if (x != 0 || y != 0 || image.getWidth() != getActualWidth() || image.getHeight() != getActualHeight()) {
      int levels = has_mipmaps ? getMipmapLevels() : 1;
      Image img(getInternalFormat(), getActualWidth(), getActualHeight(), levels);
      updateTextureData(img, 0, 0);
    }
  }

  if (image.getInternalFormat() == getInternalFormat() ||
      (image.getInternalFormat() == RGB8 && getInternalFormat() == RGBA8)) {
    updateTextureData(image, x, y);
  } else {
    cerr << "OpenGLTexture: doing online image conversion from " << int(image.getInternalFormat()) << " to " << int(getInternalFormat()) << " (SLOW)\n";
    auto tmp_image = image.convert(getInternalFormat());
    updateTextureData(*tmp_image, x, y);
  }

  // if the image has only one level, and mipmaps are needed, generate them
  if (has_mipmaps && image.getLevels() == 1) {
    need_mipmaps = true;
  }
}

void
OpenGLTexture::generateMipmaps() {
  if (need_mipmaps) {
    if (getInternalFormat() != RGB_DXT1 && getInternalFormat() != RGB_ETC1 && getInternalFormat() != LA44 && getInternalFormat() != RED_RGTC1 && getInternalFormat() != RG_RGTC2) {
      glGenerateMipmap(GL_TEXTURE_2D);
    } else {
      cerr << "unable to generate mipmaps for compressed texture!\n";
    }
    need_mipmaps = false;
  }
}

void
OpenGLTexture::releaseTextures() {
  if (!freed_textures.empty()) {
    for (auto id : freed_textures) {
      // cerr << "deleting texture " << id << endl;
      glDeleteTextures(1, &id);
    }
    freed_textures.clear();
  }
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  assert(_internal_format);
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}

TextureRef
OpenGLTexture::createTexture(Surface & surface) {
  return TextureRef( surface.getLogicalWidth(),
		     surface.getLogicalHeight(),
		     surface.getActualWidth(),
		     surface.getActualHeight(),
		     new OpenGLTexture(surface)
		     );
}
<|endoftext|>


<commit_before>#include "FieldAccessor.h"
#include "JniLocalRef.h"
#include "ArgConverter.h"
#include "NativeScriptAssert.h"
#include "Util.h"
#include "V8GlobalHelpers.h"
#include <assert.h>

using namespace v8;
using namespace std;
using namespace tns;

void FieldAccessor::Init(JavaVM *jvm, ObjectManager *objectManager)
{
	this->jvm = jvm;
	this->objectManager = objectManager;
}

Local<Value> FieldAccessor::GetJavaField(const Local<Object>& target, FieldCallbackData *fieldData)
{
	JEnv env;

	auto isolate = Isolate::GetCurrent();
	EscapableHandleScope handleScope(isolate);

	Local<Value> fieldResult;

	jweak targetJavaObject;

	const auto& fieldTypeName = fieldData->signature;
	auto isStatic = fieldData->isStatic;

	auto isPrimitiveType = fieldTypeName.size() == 1;
	auto isFieldArray = fieldTypeName[0] == '[';

	if (fieldData->fid == nullptr)
	{
		auto fieldJniSig = isPrimitiveType
								? fieldTypeName
								: (isFieldArray
									? fieldTypeName
									: ("L" + fieldTypeName + ";"));

		if (isStatic)
		{
			fieldData->clazz = env.FindClass(fieldData->declaringType);
			fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
		}
		else
		{
			fieldData->clazz = env.FindClass(fieldData->declaringType);
			fieldData->fid = env.GetFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
		}
	}

	if (!isStatic)
	{
		targetJavaObject = objectManager->GetJavaObjectByJsObject(target);
	}

	auto fieldId = fieldData->fid;
	auto clazz = fieldData->clazz;

	if (isPrimitiveType)
	{
		switch (fieldTypeName[0])
		{
			case 'Z': //bool
			{
				jboolean result;
				if (isStatic)
				{
					result = env.GetStaticBooleanField(clazz, fieldId);
				}
				else
				{
					result = env.GetBooleanField(targetJavaObject, fieldId);
				}
				fieldResult = Boolean::New(isolate, (result == JNI_TRUE));
				break;
			}
			case 'B': //byte
			{
				jbyte result;
				if (isStatic)
				{
					result = env.GetStaticByteField(clazz, fieldId);
				}
				else
				{
					result = env.GetByteField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Int32::New(isolate, result));
				break;
			}
			case 'C': //char
			{
				jchar result;
				if (isStatic)
				{
					result = env.GetStaticCharField(clazz, fieldId);
				}
				else
				{
					result = env.GetCharField(targetJavaObject, fieldId);
				}

				JniLocalRef str(env.NewString(&result, 1));
				jboolean bol = true;
				const char* resP = env.GetStringUTFChars(str, &bol);
				fieldResult = handleScope.Escape(ConvertToV8String(resP, 1));
				env.ReleaseStringUTFChars(str, resP);
				break;
			}
			case 'S': //short
			{
				jshort result;
				if (isStatic)
				{
					result = env.GetStaticShortField(clazz, fieldId);
				}
				else
				{
					result = env.GetShortField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Int32::New(isolate, result));
				break;
			}
			case 'I': //int
			{
				jint result;
				if (isStatic)
				{
					result = env.GetStaticIntField(clazz, fieldId);
				}
				else
				{
					result = env.GetIntField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Int32::New(isolate, result));
				break;

			}
			case 'J': //long
			{
				jlong result;
				if (isStatic)
				{
					result = env.GetStaticLongField(clazz, fieldId);
				}
				else
				{
					result = env.GetLongField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(ArgConverter::ConvertFromJavaLong(result));
				break;
			}
			case 'F': //float
			{
				jfloat result;
				if (isStatic)
				{
					result = env.GetStaticFloatField(clazz, fieldId);
				}
				else
				{
					result = env.GetFloatField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Number::New(isolate, (double) result));
				break;
			}
			case 'D': //double
			{
				jdouble result;
				if (isStatic)
				{
					result = env.GetStaticDoubleField(clazz, fieldId);
				}
				else
				{
					result = env.GetDoubleField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Number::New(isolate, result));
				break;
			}
			default:
			{
				// TODO:
				ASSERT_FAIL("Unknown field type");
				break;
			}
		}
	}
	else
	{
		jobject result;

		if (isStatic)
		{
			result = env.GetStaticObjectField(clazz, fieldId);
		}
		else
		{
			result = env.GetObjectField(targetJavaObject, fieldId);
		}

		if(result != nullptr) {

			bool isString = fieldTypeName == "java/lang/String";
			if (isString)
			{
				auto resultV8Value = ArgConverter::jstringToV8String((jstring)result);
				fieldResult = handleScope.Escape(resultV8Value);
			}
			else
			{
				int javaObjectID = objectManager->GetOrCreateObjectId(result);
				auto objectResult = objectManager->GetJsObjectByJavaObject(javaObjectID);

				if (objectResult.IsEmpty())
				{
					objectResult = objectManager->CreateJSWrapper(javaObjectID, fieldTypeName, result);
				}

				fieldResult = handleScope.Escape(objectResult);
			}
			env.DeleteLocalRef(result);
		}
		else
		{
			fieldResult = handleScope.Escape(Null(isolate));
		}
	}
	return fieldResult;
}

void FieldAccessor::SetJavaField(const Local<Object>& target, const Local<Value>& value, FieldCallbackData *fieldData)
{
	JEnv env;

	auto isolate = Isolate::GetCurrent();
	HandleScope handleScope(isolate);

	jweak targetJavaObject;

	const auto& fieldTypeName = fieldData->signature;
	auto isStatic = fieldData->isStatic;

	auto isPrimitiveType = fieldTypeName.size() == 1;
	auto isFieldArray = fieldTypeName[0] == '[';

	if (fieldData->fid == nullptr)
	{
		auto fieldJniSig = isPrimitiveType
								? fieldTypeName
								: (isFieldArray
									? fieldTypeName
									: ("L" + fieldTypeName + ";"));

		if (isStatic)
		{
			fieldData->clazz = env.FindClass(fieldData->declaringType);
			assert(fieldData->clazz != nullptr);
			fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
			assert(fieldData->fid != nullptr);
		}
		else
		{
			fieldData->clazz = env.FindClass(fieldData->declaringType);
			assert(fieldData->clazz != nullptr);
			fieldData->fid = env.GetFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
			assert(fieldData->fid != nullptr);
		}
	}

	if (!isStatic)
	{
		targetJavaObject = objectManager->GetJavaObjectByJsObject(target);
	}

	auto fieldId = fieldData->fid;
	auto clazz = fieldData->clazz;

	if (isPrimitiveType)
	{
		switch (fieldTypeName[0])
		{
			case 'Z': //bool
			{
				//TODO: validate value is a boolean before calling
				if (isStatic)
				{
					env.SetStaticBooleanField(clazz, fieldId, value->BooleanValue());
				}
				else
				{
					env.SetBooleanField(targetJavaObject, fieldId, value->BooleanValue());
				}
				break;
			}
			case 'B': //byte
			{
				//TODO: validate value is a byte before calling
				if (isStatic)
				{
					env.SetStaticByteField(clazz, fieldId, value->Int32Value());
				}
				else
				{
					env.SetByteField(targetJavaObject, fieldId, value->Int32Value());
				}
				break;
			}
			case 'C': //char
			{
				//TODO: validate value is a single char
				String::Utf8Value stringValue(value->ToString());
				JniLocalRef value(env.NewStringUTF(*stringValue));
				const char* chars = env.GetStringUTFChars(value, 0);

				if (isStatic)
				{
					env.SetStaticCharField(clazz, fieldId, chars[0]);
				}
				else
				{
					env.SetCharField(targetJavaObject, fieldId, chars[0]);
				}
				env.ReleaseStringUTFChars(value, chars);
				break;
			}
			case 'S': //short
			{
				//TODO: validate value is a short before calling
				if (isStatic)
				{
					env.SetStaticShortField(clazz, fieldId, value->Int32Value());
				}
				else
				{
					env.SetShortField(targetJavaObject, fieldId, value->Int32Value());
				}
				break;
			}
			case 'I': //int
			{
				//TODO: validate value is a int before calling
				if (isStatic)
				{
					env.SetStaticIntField(clazz, fieldId, value->Int32Value());
				}
				else
				{
					env.SetIntField(targetJavaObject, fieldId, value->Int32Value());
				}
				break;

			}
			case 'J': //long
			{
				jlong longValue = static_cast<jlong>(ArgConverter::ConvertToJavaLong(value));
				if (isStatic)
				{
					env.SetStaticLongField(clazz, fieldId, longValue);
				}
				else
				{
					env.SetLongField(targetJavaObject, fieldId, longValue);
				}
				break;
			}
			case 'F': //float
			{
				if (isStatic)
				{
					env.SetStaticFloatField(clazz, fieldId, static_cast<jfloat>(value->NumberValue()));
				}
				else
				{
					env.SetFloatField(targetJavaObject, fieldId, static_cast<jfloat>(value->NumberValue()));
				}
				break;
			}
			case 'D': //double
			{
				if (isStatic)
				{
					env.SetStaticDoubleField(clazz, fieldId, value->NumberValue());
				}
				else
				{
					env.SetDoubleField(targetJavaObject, fieldId, value->NumberValue());
				}
				break;
			}
			default:
			{
				// TODO:
				ASSERT_FAIL("Unknown field type");
				break;
			}
		}
	}
	else
	{
		bool isString = fieldTypeName == "java/lang/String";
		jobject result = nullptr;

		if(!value->IsNull()) {
			if (isString)
			{
				//TODO: validate valie is a string;
				String::Utf8Value stringValue(value);
				result = env.NewStringUTF(*stringValue);
			}
			else
			{
				auto objectWithHiddenID = value->ToObject();
				result =objectManager->GetJavaObjectByJsObject(objectWithHiddenID);
			}
		}

		if (isStatic)
		{
			env.SetStaticObjectField(clazz, fieldId, result);
		}
		else
		{
			env.SetObjectField(targetJavaObject, fieldId, result);
		}

		if (isString)
		{
			env.DeleteLocalRef(result);
		}
	}
}
<commit_msg>fixed string conversion<commit_after>#include "FieldAccessor.h"
#include "JniLocalRef.h"
#include "ArgConverter.h"
#include "NativeScriptAssert.h"
#include "Util.h"
#include "V8GlobalHelpers.h"
#include <assert.h>

using namespace v8;
using namespace std;
using namespace tns;

void FieldAccessor::Init(JavaVM *jvm, ObjectManager *objectManager)
{
	this->jvm = jvm;
	this->objectManager = objectManager;
}

Local<Value> FieldAccessor::GetJavaField(const Local<Object>& target, FieldCallbackData *fieldData)
{
	JEnv env;

	auto isolate = Isolate::GetCurrent();
	EscapableHandleScope handleScope(isolate);

	Local<Value> fieldResult;

	jweak targetJavaObject;

	const auto& fieldTypeName = fieldData->signature;
	auto isStatic = fieldData->isStatic;

	auto isPrimitiveType = fieldTypeName.size() == 1;
	auto isFieldArray = fieldTypeName[0] == '[';

	if (fieldData->fid == nullptr)
	{
		auto fieldJniSig = isPrimitiveType
								? fieldTypeName
								: (isFieldArray
									? fieldTypeName
									: ("L" + fieldTypeName + ";"));

		if (isStatic)
		{
			fieldData->clazz = env.FindClass(fieldData->declaringType);
			fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
		}
		else
		{
			fieldData->clazz = env.FindClass(fieldData->declaringType);
			fieldData->fid = env.GetFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
		}
	}

	if (!isStatic)
	{
		targetJavaObject = objectManager->GetJavaObjectByJsObject(target);
	}

	auto fieldId = fieldData->fid;
	auto clazz = fieldData->clazz;

	if (isPrimitiveType)
	{
		switch (fieldTypeName[0])
		{
			case 'Z': //bool
			{
				jboolean result;
				if (isStatic)
				{
					result = env.GetStaticBooleanField(clazz, fieldId);
				}
				else
				{
					result = env.GetBooleanField(targetJavaObject, fieldId);
				}
				fieldResult = Boolean::New(isolate, (result == JNI_TRUE));
				break;
			}
			case 'B': //byte
			{
				jbyte result;
				if (isStatic)
				{
					result = env.GetStaticByteField(clazz, fieldId);
				}
				else
				{
					result = env.GetByteField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Int32::New(isolate, result));
				break;
			}
			case 'C': //char
			{
				jchar result;
				if (isStatic)
				{
					result = env.GetStaticCharField(clazz, fieldId);
				}
				else
				{
					result = env.GetCharField(targetJavaObject, fieldId);
				}

				JniLocalRef str(env.NewString(&result, 1));
				jboolean bol = true;
				const char* resP = env.GetStringUTFChars(str, &bol);
				fieldResult = handleScope.Escape(ConvertToV8String(resP, 1));
				env.ReleaseStringUTFChars(str, resP);
				break;
			}
			case 'S': //short
			{
				jshort result;
				if (isStatic)
				{
					result = env.GetStaticShortField(clazz, fieldId);
				}
				else
				{
					result = env.GetShortField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Int32::New(isolate, result));
				break;
			}
			case 'I': //int
			{
				jint result;
				if (isStatic)
				{
					result = env.GetStaticIntField(clazz, fieldId);
				}
				else
				{
					result = env.GetIntField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Int32::New(isolate, result));
				break;

			}
			case 'J': //long
			{
				jlong result;
				if (isStatic)
				{
					result = env.GetStaticLongField(clazz, fieldId);
				}
				else
				{
					result = env.GetLongField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(ArgConverter::ConvertFromJavaLong(result));
				break;
			}
			case 'F': //float
			{
				jfloat result;
				if (isStatic)
				{
					result = env.GetStaticFloatField(clazz, fieldId);
				}
				else
				{
					result = env.GetFloatField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Number::New(isolate, (double) result));
				break;
			}
			case 'D': //double
			{
				jdouble result;
				if (isStatic)
				{
					result = env.GetStaticDoubleField(clazz, fieldId);
				}
				else
				{
					result = env.GetDoubleField(targetJavaObject, fieldId);
				}
				fieldResult = handleScope.Escape(Number::New(isolate, result));
				break;
			}
			default:
			{
				// TODO:
				ASSERT_FAIL("Unknown field type");
				break;
			}
		}
	}
	else
	{
		jobject result;

		if (isStatic)
		{
			result = env.GetStaticObjectField(clazz, fieldId);
		}
		else
		{
			result = env.GetObjectField(targetJavaObject, fieldId);
		}

		if(result != nullptr) {

			bool isString = fieldTypeName == "java/lang/String";
			if (isString)
			{
				auto resultV8Value = ArgConverter::jstringToV8String((jstring)result);
				fieldResult = handleScope.Escape(resultV8Value);
			}
			else
			{
				int javaObjectID = objectManager->GetOrCreateObjectId(result);
				auto objectResult = objectManager->GetJsObjectByJavaObject(javaObjectID);

				if (objectResult.IsEmpty())
				{
					objectResult = objectManager->CreateJSWrapper(javaObjectID, fieldTypeName, result);
				}

				fieldResult = handleScope.Escape(objectResult);
			}
			env.DeleteLocalRef(result);
		}
		else
		{
			fieldResult = handleScope.Escape(Null(isolate));
		}
	}
	return fieldResult;
}

void FieldAccessor::SetJavaField(const Local<Object>& target, const Local<Value>& value, FieldCallbackData *fieldData)
{
	JEnv env;

	auto isolate = Isolate::GetCurrent();
	HandleScope handleScope(isolate);

	jweak targetJavaObject;

	const auto& fieldTypeName = fieldData->signature;
	auto isStatic = fieldData->isStatic;

	auto isPrimitiveType = fieldTypeName.size() == 1;
	auto isFieldArray = fieldTypeName[0] == '[';

	if (fieldData->fid == nullptr)
	{
		auto fieldJniSig = isPrimitiveType
								? fieldTypeName
								: (isFieldArray
									? fieldTypeName
									: ("L" + fieldTypeName + ";"));

		if (isStatic)
		{
			fieldData->clazz = env.FindClass(fieldData->declaringType);
			assert(fieldData->clazz != nullptr);
			fieldData->fid = env.GetStaticFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
			assert(fieldData->fid != nullptr);
		}
		else
		{
			fieldData->clazz = env.FindClass(fieldData->declaringType);
			assert(fieldData->clazz != nullptr);
			fieldData->fid = env.GetFieldID(fieldData->clazz, fieldData->name, fieldJniSig);
			assert(fieldData->fid != nullptr);
		}
	}

	if (!isStatic)
	{
		targetJavaObject = objectManager->GetJavaObjectByJsObject(target);
	}

	auto fieldId = fieldData->fid;
	auto clazz = fieldData->clazz;

	if (isPrimitiveType)
	{
		switch (fieldTypeName[0])
		{
			case 'Z': //bool
			{
				//TODO: validate value is a boolean before calling
				if (isStatic)
				{
					env.SetStaticBooleanField(clazz, fieldId, value->BooleanValue());
				}
				else
				{
					env.SetBooleanField(targetJavaObject, fieldId, value->BooleanValue());
				}
				break;
			}
			case 'B': //byte
			{
				//TODO: validate value is a byte before calling
				if (isStatic)
				{
					env.SetStaticByteField(clazz, fieldId, value->Int32Value());
				}
				else
				{
					env.SetByteField(targetJavaObject, fieldId, value->Int32Value());
				}
				break;
			}
			case 'C': //char
			{
				//TODO: validate value is a single char
				String::Utf8Value stringValue(value->ToString());
				JniLocalRef value(env.NewStringUTF(*stringValue));
				const char* chars = env.GetStringUTFChars(value, 0);

				if (isStatic)
				{
					env.SetStaticCharField(clazz, fieldId, chars[0]);
				}
				else
				{
					env.SetCharField(targetJavaObject, fieldId, chars[0]);
				}
				env.ReleaseStringUTFChars(value, chars);
				break;
			}
			case 'S': //short
			{
				//TODO: validate value is a short before calling
				if (isStatic)
				{
					env.SetStaticShortField(clazz, fieldId, value->Int32Value());
				}
				else
				{
					env.SetShortField(targetJavaObject, fieldId, value->Int32Value());
				}
				break;
			}
			case 'I': //int
			{
				//TODO: validate value is a int before calling
				if (isStatic)
				{
					env.SetStaticIntField(clazz, fieldId, value->Int32Value());
				}
				else
				{
					env.SetIntField(targetJavaObject, fieldId, value->Int32Value());
				}
				break;

			}
			case 'J': //long
			{
				jlong longValue = static_cast<jlong>(ArgConverter::ConvertToJavaLong(value));
				if (isStatic)
				{
					env.SetStaticLongField(clazz, fieldId, longValue);
				}
				else
				{
					env.SetLongField(targetJavaObject, fieldId, longValue);
				}
				break;
			}
			case 'F': //float
			{
				if (isStatic)
				{
					env.SetStaticFloatField(clazz, fieldId, static_cast<jfloat>(value->NumberValue()));
				}
				else
				{
					env.SetFloatField(targetJavaObject, fieldId, static_cast<jfloat>(value->NumberValue()));
				}
				break;
			}
			case 'D': //double
			{
				if (isStatic)
				{
					env.SetStaticDoubleField(clazz, fieldId, value->NumberValue());
				}
				else
				{
					env.SetDoubleField(targetJavaObject, fieldId, value->NumberValue());
				}
				break;
			}
			default:
			{
				// TODO:
				ASSERT_FAIL("Unknown field type");
				break;
			}
		}
	}
	else
	{
		bool isString = fieldTypeName == "java/lang/String";
		jobject result = nullptr;

		if(!value->IsNull()) {
			if (isString)
			{
				//TODO: validate valie is a string;
				result = ConvertToJavaString(value);
			}
			else
			{
				auto objectWithHiddenID = value->ToObject();
				result =objectManager->GetJavaObjectByJsObject(objectWithHiddenID);
			}
		}

		if (isStatic)
		{
			env.SetStaticObjectField(clazz, fieldId, result);
		}
		else
		{
			env.SetObjectField(targetJavaObject, fieldId, result);
		}

		if (isString)
		{
			env.DeleteLocalRef(result);
		}
	}
}
<|endoftext|>


<commit_before>#include "OpenGLTexture.h"

#include "TextureRef.h"
#include "Image.h"
#include "Surface.h"

#define GL_GLEXT_PROTOTYPES

#if defined __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#elif (defined GL_ES)
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#else
#define GL_GLEXT_PROTOTYPES

#ifdef _WIN32
#include <GL/glew.h>
#include <windows.h>
#endif

#ifdef ANDROID
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#else
#include <GL/gl.h>

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif
#endif

#endif

#if defined __APPLE__ || defined ANDROID
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0
#endif
#ifndef GL_COMPRESSED_RED_RGTC1
#define GL_COMPRESSED_RED_RGTC1 0x8DBB
#endif
#ifndef GL_COMPRESSED_RG_RGTC2
#define GL_COMPRESSED_RG_RGTC2 0x8DBD
#endif
#endif

#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;
bool OpenGLTexture::global_init = false;

OpenGLTexture::OpenGLTexture(Surface & surface)
  : Texture(surface.getLogicalWidth(), surface.getLogicalHeight(), surface.getActualWidth(), surface.getActualHeight(), surface.getMinFilter(), surface.getMagFilter(), surface.getTargetFormat(), 1) {
  assert(getInternalFormat());
  auto image = surface.createImage();
  updateData(*image, 0, 0);
}

static GLenum getOpenGLInternalFormat(InternalFormat internal_format) {
  switch (internal_format) {
  case R8: return GL_R8;
  case RG8: return GL_RG8;
  case RGB565: return GL_RGB565;
  case RGBA4: return GL_RGBA4;
  case RGBA8: return GL_RGBA8;
  case RGB8: return GL_RGB8;
  case RGB8_24: return GL_RGBA8;
  case RED_RGTC1: return GL_COMPRESSED_RED_RGTC1;
  case RG_RGTC2: return GL_COMPRESSED_RG_RGTC2;
  case RGB_ETC1: return GL_COMPRESSED_RGB8_ETC2;
  case RGB_DXT1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
  case RGBA_DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  case LUMINANCE_ALPHA: return GL_RG8;
  case LA44: return GL_R8; // pack luminance and alpha to single byte
  case R32F: return GL_R32F;

  }
  assert(0);
  return 0;
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateCompressedData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  GLenum format = getOpenGLInternalFormat(getInternalFormat());
  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    // cerr << "compressed tex: x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", offset = " << offset << ", size = " << size << endl;
    glCompressedTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, format, size, image.getData() + offset);
    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }
}

void
OpenGLTexture::updatePlainData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  GLenum format = getOpenGLInternalFormat(getInternalFormat());

  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    // cerr << "plain tex: x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", size = " << size << ", offset = " << offset << endl;

    if (getInternalFormat() == RGBA8) {
#if defined __APPLE__ || defined ANDROID
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RGBA, GL_UNSIGNED_BYTE, image.getData() + offset);
#else
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image.getData() + offset);
      // glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image.getWidth(), height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, image.getData());
#endif
    } else if (getInternalFormat() == LA44) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RED, GL_UNSIGNED_BYTE, image.getData() + offset);
    } else if (getInternalFormat() == RGB565) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, image.getData() + offset);
    } else if (getInternalFormat() == R32F) {
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, current_width, current_height, GL_RED, GL_FLOAT, image.getData() + offset);
    } else {
      cerr << "unhandled format " << int(getInternalFormat()) << endl;
      assert(0);
    }

    // glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, getOpenGLInternalFormat(getInternalFormat()), size, image.getData() + offset);

    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }
}

void
OpenGLTexture::updateData(const Image & image, unsigned int x, unsigned int y) {
  if (!global_init) {
    global_init = true;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  }

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    cerr << "created texture id " << texture_id << " (total = " << total_textures << ")" << endl;
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, getOpenGLInternalFormat(getInternalFormat()), getActualWidth(), getActualHeight());

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));

    if (x != 0 || y != 0 || image.getWidth() != getActualWidth() || image.getHeight() != getActualHeight()) {
      int levels = has_mipmaps ? getMipmapLevels() : 1;
      if (getInternalFormat() == RGB_ETC1) {
	Image img(ImageFormat::RGB_ETC1, getActualWidth(), getActualHeight(), levels);
	updateCompressedData(img, 0, 0);
      } else if (getInternalFormat() == RGB_DXT1) {
	Image img(ImageFormat::RGB_DXT1, getActualWidth(), getActualHeight(), levels);
	updateCompressedData(img, 0, 0);
      } else if (getInternalFormat() == RGBA8) {
	Image img(ImageFormat::RGBA32, getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else if (getInternalFormat() == LA44) {
	Image img(ImageFormat::LA44, getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else if (getInternalFormat() == RGB565) {
	Image img(ImageFormat::RGB565, getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else if (getInternalFormat() == R32F) {
	assert(levels == 1);
	Image img(ImageFormat::FLOAT32, getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else {
	assert(0);
      }
    }
  }

  if (getInternalFormat() == R32F) {
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RED, GL_FLOAT, image.getData());
  } else if (getInternalFormat() == R8) {
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RED, GL_UNSIGNED_BYTE, image.getData());
  } else if (getInternalFormat() == LA44) {
    auto tmp_image = image.convert(ImageFormat::LA44);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RED, GL_UNSIGNED_BYTE, tmp_image->getData());
  } else if (getInternalFormat() == LUMINANCE_ALPHA) {
    if (image.getFormat() == ImageFormat::LA88) {
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RG, GL_UNSIGNED_BYTE, image.getData());
    } else {
      auto tmp_image = image.convert(ImageFormat::LA88);
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RG, GL_UNSIGNED_BYTE, tmp_image->getData());
    }
  } else if (getInternalFormat() == RGB565) {
    auto tmp_image = image.convert(ImageFormat::RGB565);
    updatePlainData(*tmp_image, x, y);
    // glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tmp_image->getData());
  } else if (getInternalFormat() == RGBA4) {
    auto tmp_image = image.convert(ImageFormat::RGBA4);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, tmp_image->getData());
  } else if (getInternalFormat() == RGB_ETC1) {
    if (image.getFormat().getCompression() == ImageFormat::ETC1) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(ImageFormat::RGB_ETC1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RGB_DXT1) {
    if (image.getFormat().getCompression() == ImageFormat::DXT1) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(ImageFormat::RGB_DXT1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RG_RGTC2) {
    if (image.getFormat().getCompression() == ImageFormat::RGTC2) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(ImageFormat::RG_RGTC2);
      updateCompressedData(*tmp_image, x, y);
    }
  } else {
    updatePlainData(image, x, y);
  }

  if (has_mipmaps && image.getLevels() == 1) {
    need_mipmaps = true;
  }

  glBindTexture(GL_TEXTURE_2D, 0);
}

void
OpenGLTexture::generateMipmaps() {
  if (need_mipmaps) {
    if (getInternalFormat() != RGB_DXT1 && getInternalFormat() != RGB_ETC1 && getInternalFormat() != LA44 && getInternalFormat() != RED_RGTC1 && getInternalFormat() != RG_RGTC2) {
      glGenerateMipmap(GL_TEXTURE_2D);
    } else {
      cerr << "unable to generate mipmaps for compressed texture!\n";
    }
    need_mipmaps = false;
  }
}

void
OpenGLTexture::releaseTextures() {
  if (!freed_textures.empty()) {
    cerr << "DELETING TEXTURES: " << OpenGLTexture::getFreedTextures().size() << "/" << OpenGLTexture::getNumTextures() << endl;

    for (vector<unsigned int>::const_iterator it = freed_textures.begin(); it != freed_textures.end(); it++) {
      GLuint texid = *it;
      glDeleteTextures(1, &texid);
    }
    freed_textures.clear();
  }
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  assert(_internal_format);
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}

TextureRef
OpenGLTexture::createTexture(Surface & surface) {
  return TextureRef( surface.getLogicalWidth(),
		     surface.getLogicalHeight(),
		     surface.getActualWidth(),
		     surface.getActualHeight(),
		     new OpenGLTexture(surface)
		     );
}
<commit_msg>add assert<commit_after>#include "OpenGLTexture.h"

#include "TextureRef.h"
#include "Image.h"
#include "Surface.h"

#define GL_GLEXT_PROTOTYPES

#if defined __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#elif (defined GL_ES)
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#else
#define GL_GLEXT_PROTOTYPES

#ifdef _WIN32
#include <GL/glew.h>
#include <windows.h>
#endif

#ifdef ANDROID
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#else
#include <GL/gl.h>

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif
#endif

#endif

#if defined __APPLE__ || defined ANDROID
#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0
#endif
#ifndef GL_COMPRESSED_RED_RGTC1
#define GL_COMPRESSED_RED_RGTC1 0x8DBB
#endif
#ifndef GL_COMPRESSED_RG_RGTC2
#define GL_COMPRESSED_RG_RGTC2 0x8DBD
#endif
#endif

#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;
bool OpenGLTexture::global_init = false;

OpenGLTexture::OpenGLTexture(Surface & surface)
  : Texture(surface.getLogicalWidth(), surface.getLogicalHeight(), surface.getActualWidth(), surface.getActualHeight(), surface.getMinFilter(), surface.getMagFilter(), surface.getTargetFormat(), 1) {
  assert(getInternalFormat());
  auto image = surface.createImage();
  updateData(*image, 0, 0);
}

static GLenum getOpenGLInternalFormat(InternalFormat internal_format) {
  switch (internal_format) {
  case R8: return GL_R8;
  case RG8: return GL_RG8;
  case RGB565: return GL_RGB565;
  case RGBA4: return GL_RGBA4;
  case RGBA8: return GL_RGBA8;
  case RGB8: return GL_RGB8;
  case RGB8_24: return GL_RGBA8;
  case RED_RGTC1: return GL_COMPRESSED_RED_RGTC1;
  case RG_RGTC2: return GL_COMPRESSED_RG_RGTC2;
  case RGB_ETC1: return GL_COMPRESSED_RGB8_ETC2;
  case RGB_DXT1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
  case RGBA_DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  case LUMINANCE_ALPHA: return GL_RG8;
  case LA44: return GL_R8; // pack luminance and alpha to single byte
  case R32F: return GL_R32F;

  }
  assert(0);
  return 0;
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateCompressedData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  GLenum format = getOpenGLInternalFormat(getInternalFormat());
  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    // cerr << "compressed tex: x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", offset = " << offset << ", size = " << size << endl;
    glCompressedTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, format, size, image.getData() + offset);
    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }
}

void
OpenGLTexture::updatePlainData(const Image & image, unsigned int x, unsigned int y) {
  unsigned int offset = 0;
  unsigned int current_width = image.getWidth(), current_height = image.getHeight();
  GLenum format = getOpenGLInternalFormat(getInternalFormat());

  for (unsigned int level = 0; level < image.getLevels(); level++) {
    size_t size = image.calculateOffset(level + 1) - image.calculateOffset(level);
    // cerr << "plain tex: x = " << x << ", y = " << y << ", l = " << (level+1) << "/" << image.getLevels() << ", w = " << current_width << ", h = " << current_height << ", size = " << size << ", offset = " << offset << endl;

    if (getInternalFormat() == RGBA8) {
      assert(image.getData());
#if defined __APPLE__ || defined ANDROID
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RGBA, GL_UNSIGNED_BYTE, image.getData() + offset);
#else
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image.getData() + offset);
      // glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image.getWidth(), height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, image.getData());
#endif
    } else if (getInternalFormat() == LA44) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RED, GL_UNSIGNED_BYTE, image.getData() + offset);
    } else if (getInternalFormat() == RGB565) {
      glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, image.getData() + offset);
    } else if (getInternalFormat() == R32F) {
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, current_width, current_height, GL_RED, GL_FLOAT, image.getData() + offset);
    } else {
      cerr << "unhandled format " << int(getInternalFormat()) << endl;
      assert(0);
    }

    // glTexSubImage2D(GL_TEXTURE_2D, level, x, y, current_width, current_height, getOpenGLInternalFormat(getInternalFormat()), size, image.getData() + offset);

    offset += size;
    current_width /= 2;
    current_height /= 2;
    x /= 2;
    y /= 2;
  }
}

void
OpenGLTexture::updateData(const Image & image, unsigned int x, unsigned int y) {
  if (!global_init) {
    global_init = true;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  }

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    cerr << "created texture id " << texture_id << " (total = " << total_textures << ")" << endl;
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, getOpenGLInternalFormat(getInternalFormat()), getActualWidth(), getActualHeight());

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));

    if (x != 0 || y != 0 || image.getWidth() != getActualWidth() || image.getHeight() != getActualHeight()) {
      int levels = has_mipmaps ? getMipmapLevels() : 1;
      if (getInternalFormat() == RGB_ETC1) {
	Image img(ImageFormat::RGB_ETC1, getActualWidth(), getActualHeight(), levels);
	updateCompressedData(img, 0, 0);
      } else if (getInternalFormat() == RGB_DXT1) {
	Image img(ImageFormat::RGB_DXT1, getActualWidth(), getActualHeight(), levels);
	updateCompressedData(img, 0, 0);
      } else if (getInternalFormat() == RGBA8) {
	Image img(ImageFormat::RGBA32, getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else if (getInternalFormat() == LA44) {
	Image img(ImageFormat::LA44, getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else if (getInternalFormat() == RGB565) {
	Image img(ImageFormat::RGB565, getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else if (getInternalFormat() == R32F) {
	assert(levels == 1);
	Image img(ImageFormat::FLOAT32, getActualWidth(), getActualHeight(), levels);
	updatePlainData(img, 0, 0);
      } else {
	assert(0);
      }
    }
  }

  if (getInternalFormat() == R32F) {
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RED, GL_FLOAT, image.getData());
  } else if (getInternalFormat() == R8) {
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RED, GL_UNSIGNED_BYTE, image.getData());
  } else if (getInternalFormat() == LA44) {
    auto tmp_image = image.convert(ImageFormat::LA44);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RED, GL_UNSIGNED_BYTE, tmp_image->getData());
  } else if (getInternalFormat() == LUMINANCE_ALPHA) {
    if (image.getFormat() == ImageFormat::LA88) {
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, image.getWidth(), image.getHeight(), GL_RG, GL_UNSIGNED_BYTE, image.getData());
    } else {
      auto tmp_image = image.convert(ImageFormat::LA88);
      glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RG, GL_UNSIGNED_BYTE, tmp_image->getData());
    }
  } else if (getInternalFormat() == RGB565) {
    auto tmp_image = image.convert(ImageFormat::RGB565);
    updatePlainData(*tmp_image, x, y);
    // glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tmp_image->getData());
  } else if (getInternalFormat() == RGBA4) {
    auto tmp_image = image.convert(ImageFormat::RGBA4);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, tmp_image->getWidth(), tmp_image->getHeight(), GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, tmp_image->getData());
  } else if (getInternalFormat() == RGB_ETC1) {
    if (image.getFormat().getCompression() == ImageFormat::ETC1) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(ImageFormat::RGB_ETC1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RGB_DXT1) {
    if (image.getFormat().getCompression() == ImageFormat::DXT1) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(ImageFormat::RGB_DXT1);
      updateCompressedData(*tmp_image, x, y);
    }
  } else if (getInternalFormat() == RG_RGTC2) {
    if (image.getFormat().getCompression() == ImageFormat::RGTC2) {
      updateCompressedData(image, x, y);
    } else {
      cerr << "WARNING: compression should be done in thread\n";
      auto tmp_image = image.convert(ImageFormat::RG_RGTC2);
      updateCompressedData(*tmp_image, x, y);
    }
  } else {
    updatePlainData(image, x, y);
  }

  if (has_mipmaps && image.getLevels() == 1) {
    need_mipmaps = true;
  }

  glBindTexture(GL_TEXTURE_2D, 0);
}

void
OpenGLTexture::generateMipmaps() {
  if (need_mipmaps) {
    if (getInternalFormat() != RGB_DXT1 && getInternalFormat() != RGB_ETC1 && getInternalFormat() != LA44 && getInternalFormat() != RED_RGTC1 && getInternalFormat() != RG_RGTC2) {
      glGenerateMipmap(GL_TEXTURE_2D);
    } else {
      cerr << "unable to generate mipmaps for compressed texture!\n";
    }
    need_mipmaps = false;
  }
}

void
OpenGLTexture::releaseTextures() {
  if (!freed_textures.empty()) {
    cerr << "DELETING TEXTURES: " << OpenGLTexture::getFreedTextures().size() << "/" << OpenGLTexture::getNumTextures() << endl;

    for (vector<unsigned int>::const_iterator it = freed_textures.begin(); it != freed_textures.end(); it++) {
      GLuint texid = *it;
      glDeleteTextures(1, &texid);
    }
    freed_textures.clear();
  }
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  assert(_internal_format);
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}

TextureRef
OpenGLTexture::createTexture(Surface & surface) {
  return TextureRef( surface.getLogicalWidth(),
		     surface.getLogicalHeight(),
		     surface.getActualWidth(),
		     surface.getActualHeight(),
		     new OpenGLTexture(surface)
		     );
}
<|endoftext|>


<commit_before>#include <Render/Pipelining/Buffer/Renderbuffer.hh>
#include <utility>

namespace AGE
{

	Renderbuffer::Renderbuffer(GLint width, GLint height, GLenum internal_format) :
		_id(0),
		_width(width),
		_height(height),
		_internal_format(internal_format)
	{
		glGenRenderbuffers(1, &_id);
		bind();
		glRenderbufferStorage(GL_RENDERBUFFER, _internal_format, _width, _height);
		unbind();
	}

	Renderbuffer::Renderbuffer(Renderbuffer &&move) :
		_id(move._id),
		_width(move._width),
		_height(move._height),
		_internal_format(move._internal_format)
	{
		move._id = 0;
	}

	Renderbuffer::~Renderbuffer()
	{
		if (_id)
		{
			glDeleteRenderbuffers(1, &_id);
		}
	}

	GLenum Renderbuffer::type() const
	{
		return (GL_RENDERBUFFER);
	}

	Renderbuffer const & Renderbuffer::bind() const
	{
		glBindRenderbuffer(GL_RENDERBUFFER, _id);
		return (*this);
	}

	Renderbuffer const & Renderbuffer::unbind() const
	{
		glBindRenderbuffer(GL_RENDERBUFFER, 0);
		return (*this);
	}

	IFramebufferStorage const & Renderbuffer::attachment(Framebuffer const &framebuffer, GLenum attach) const
	{
		bind();
		glFramebufferRenderbuffer(framebuffer.type(), attach, GL_RENDERBUFFER, _id);
		unbind();
		return (*this);
	}

}<commit_msg>unbind useless<commit_after>#include <Render/Pipelining/Buffer/Renderbuffer.hh>
#include <utility>

namespace AGE
{

	Renderbuffer::Renderbuffer(GLint width, GLint height, GLenum internal_format) :
		_id(0),
		_width(width),
		_height(height),
		_internal_format(internal_format)
	{
		glGenRenderbuffers(1, &_id);
		bind();
		glRenderbufferStorage(GL_RENDERBUFFER, _internal_format, _width, _height);
		unbind();
	}

	Renderbuffer::Renderbuffer(Renderbuffer &&move) :
		_id(move._id),
		_width(move._width),
		_height(move._height),
		_internal_format(move._internal_format)
	{
		move._id = 0;
	}

	Renderbuffer::~Renderbuffer()
	{
		if (_id)
		{
			glDeleteRenderbuffers(1, &_id);
		}
	}

	GLenum Renderbuffer::type() const
	{
		return (GL_RENDERBUFFER);
	}

	Renderbuffer const & Renderbuffer::bind() const
	{
		glBindRenderbuffer(GL_RENDERBUFFER, _id);
		return (*this);
	}

	Renderbuffer const & Renderbuffer::unbind() const
	{
		glBindRenderbuffer(GL_RENDERBUFFER, 0);
		return (*this);
	}

	IFramebufferStorage const & Renderbuffer::attachment(Framebuffer const &framebuffer, GLenum attach) const
	{
		bind();
		glFramebufferRenderbuffer(framebuffer.type(), attach, GL_RENDERBUFFER, _id);
		return (*this);
	}

}<|endoftext|>