From ab0ab5ddaa8616a1d7a2bd605404ad0c921b4e57 Mon Sep 17 00:00:00 2001 From: "T2@kimikage" Date: Sun, 18 Jul 2010 20:32:56 +0900 Subject: [PATCH] =?utf8?q?NSD=E3=83=95=E3=82=A9=E3=83=B3=E3=83=88=E3=83=97?= =?utf8?q?=E3=83=A9=E3=82=B0=E3=82=A4=E3=83=B3=E7=99=BB=E9=8C=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- common/src/nslua.h | 18 +++ nsdfont/src/ArgbArray.h | 38 +++++ nsdfont/src/ArgbBitmap.cpp | 35 +++++ nsdfont/src/ArgbBitmap.h | 42 ++++++ nsdfont/src/CharacterMap.cpp | 313 ++++++++++++++++++++++++++++++++++++++ nsdfont/src/CharacterMap.h | 129 ++++++++++++++++ nsdfont/src/Color.h | 116 ++++++++++++++ nsdfont/src/ColorBlender.cpp | 51 +++++++ nsdfont/src/ColorBlender.h | 135 +++++++++++++++++ nsdfont/src/Decorator.cpp | 180 ++++++++++++++++++++++ nsdfont/src/Decorator.h | 59 ++++++++ nsdfont/src/Glyph.cpp | 225 ++++++++++++++++++++++++++++ nsdfont/src/Glyph.h | 115 ++++++++++++++ nsdfont/src/Typesetter.cpp | 88 +++++++++++ nsdfont/src/Typesetter.h | 29 ++++ nsdfont/src/UnicodeString.cpp | 340 ++++++++++++++++++++++++++++++++++++++++++ nsdfont/src/UnicodeString.h | 47 ++++++ nsdfont/src/main.cpp | 176 ++++++++++++++++++++++ nsdfont/vs2005/nsdfont.sln | 20 +++ nsdfont/vs2005/nsdfont.vcproj | 259 ++++++++++++++++++++++++++++++++ 20 files changed, 2415 insertions(+) create mode 100755 common/src/nslua.h create mode 100755 nsdfont/src/ArgbArray.h create mode 100755 nsdfont/src/ArgbBitmap.cpp create mode 100755 nsdfont/src/ArgbBitmap.h create mode 100755 nsdfont/src/CharacterMap.cpp create mode 100755 nsdfont/src/CharacterMap.h create mode 100755 nsdfont/src/Color.h create mode 100755 nsdfont/src/ColorBlender.cpp create mode 100755 nsdfont/src/ColorBlender.h create mode 100755 nsdfont/src/Decorator.cpp create mode 100755 nsdfont/src/Decorator.h create mode 100755 nsdfont/src/Glyph.cpp create mode 100755 nsdfont/src/Glyph.h create mode 100755 nsdfont/src/Typesetter.cpp create mode 100755 nsdfont/src/Typesetter.h create mode 100755 nsdfont/src/UnicodeString.cpp create mode 100755 nsdfont/src/UnicodeString.h create mode 100755 nsdfont/src/main.cpp create mode 100755 nsdfont/vs2005/nsdfont.sln create mode 100755 nsdfont/vs2005/nsdfont.vcproj diff --git a/common/src/nslua.h b/common/src/nslua.h new file mode 100755 index 0000000..dff6275 --- /dev/null +++ b/common/src/nslua.h @@ -0,0 +1,18 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +typedef void (*NL_registerPtr)( const char *name, int (*f)(lua_State *) ); +typedef void (*NL_gettablePtr)( lua_State *L, int index ); +typedef int (*NL_isstringPtr)( lua_State *L, int index ); +typedef int (*NL_istablePtr)( lua_State *L, int index ); +typedef void (*NL_popPtr)( lua_State *L, int n ); +typedef void (*NL_pushintegerPtr)( lua_State *L, int n ); +typedef void (*NL_pushstringPtr)( lua_State *L, const char *str ); +typedef int (*NL_tobooleanPtr)( lua_State *L, int index ); +typedef int (*NL_tointegerPtr)( lua_State *L, int index ); +typedef double (*NL_tonumberPtr)( lua_State *L, int index ); +typedef const char *(*NL_tostringPtr)( lua_State *L, int index ); \ No newline at end of file diff --git a/nsdfont/src/ArgbArray.h b/nsdfont/src/ArgbArray.h new file mode 100755 index 0000000..65ced82 --- /dev/null +++ b/nsdfont/src/ArgbArray.h @@ -0,0 +1,38 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#pragma once +#include "Color.h" +namespace nsdfont +{ + class ArgbArray + { + private: + Color *colors; + size_t length; + public: + + ArgbArray( unsigned char *head ) : + colors( reinterpret_cast( head ) ), + length( 0 ) + { + } + + ArgbArray( unsigned char *head, size_t length ) : + colors( reinterpret_cast( head ) ), + length( length ) + { + } + + virtual ~ArgbArray(void) + { + } + + + inline Color &operator[]( size_t i ) const { return colors[i]; } + }; +} diff --git a/nsdfont/src/ArgbBitmap.cpp b/nsdfont/src/ArgbBitmap.cpp new file mode 100755 index 0000000..717cbeb --- /dev/null +++ b/nsdfont/src/ArgbBitmap.cpp @@ -0,0 +1,35 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#include "ArgbBitmap.h" + +namespace nsdfont +{ + ArgbBitmap::ArgbBitmap( int width, int height, unsigned char *bits ) : + width( width ), + height( height ), + bits( bits ), + allocated( 0 ) + { + } + + ArgbBitmap::ArgbBitmap( int width, int height ) : + width( width ), + height( height ) + { + allocated = width * height * 4; + bits = new unsigned char[allocated](); + } + + ArgbBitmap::~ArgbBitmap( void ) + { + if ( allocated > 0 && bits ) + { + delete[] bits; + } + } +} diff --git a/nsdfont/src/ArgbBitmap.h b/nsdfont/src/ArgbBitmap.h new file mode 100755 index 0000000..d753a84 --- /dev/null +++ b/nsdfont/src/ArgbBitmap.h @@ -0,0 +1,42 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#pragma once + +#include "ArgbArray.h" + +namespace nsdfont +{ + class ArgbBitmap + { + private: + int width; + int height; + unsigned char *bits; + size_t allocated; + public: + ArgbBitmap( int width, int height, unsigned char *bits ); + ArgbBitmap( int width, int height ); + virtual ~ArgbBitmap( void ); + inline unsigned char &operator[]( size_t i ) const { return bits[i]; } + inline int getWidth( void ) const { return width; } + inline int getHeight( void ) const { return height; } + inline int getPitch( void ) const { return width * 4; } + /** + * Žw’肵‚½ˆÊ’u‚©‚ç‚̉æ‘f—ñ‚ðŽæ“¾‚·‚é. + * @param x x•ûŒü‚̈ʒu. + * @param y y•ûŒü‚̈ʒu. + * @return ‰æ‘f—ñ + * @attention ”z—ñ‚Ì‘å‚«‚³‚ɂ‚¢‚Ă̏î•ñ‚ÍŽ‚½‚È‚¢. Žg—pŽÒ‚ª’ˆÓ‚µ‚Ĉµ‚¤‚±‚Æ. + */ + inline ArgbArray getArray( int x, int y ) const + { + return ArgbArray( &bits[(x + y * width) * 4] ); + } + }; + +} diff --git a/nsdfont/src/CharacterMap.cpp b/nsdfont/src/CharacterMap.cpp new file mode 100755 index 0000000..9277180 --- /dev/null +++ b/nsdfont/src/CharacterMap.cpp @@ -0,0 +1,313 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#include "CharacterMap.h" + +// This code is based on a sample code of +// KBF241020 (http://support.microsoft.com/kb/241020/) + +namespace nsdfont +{ + CharacterMap::CharacterMap( void ) + { + hdc = CreateCompatibleDC( NULL ); + hFont = NULL; + cmapTable = NULL; + } + + CharacterMap::~CharacterMap( void ) + { + if ( NULL != hdc ) + { + DeleteDC( hdc ); + } + clearFont(); + } + + bool CharacterMap::selectFont( const LOGFONTA *font ) + { + clearFont(); + HFONT hFont = CreateFontIndirectA( font ); + SelectObject( hdc, hFont ); + + if ( !fetchUnicodeCMapTable() ) + { + clearFont(); + return false; + } + characterCount = getCharacterCount( cmapTable ); + return true; + } + + void CharacterMap::clearFont( void ) + { + if ( NULL != hFont ) + { + DeleteObject( hFont ); + hFont = NULL; + } + + delete [] cmapTable; + cmapTable = NULL; + + characterCount = 0; + } + + void CharacterMap::swapArrays( CMap4 *format4 ) + { + const USHORT *startCount = getStartCountArray( format4 ); + const USHORT *idDelta = getIdDeltaArray( format4 ); + const USHORT *idRangeOffset = getIdRangeOffsetArray( format4 ); + const USHORT *endCount = getEndCountArray( format4 ); + const USHORT *endOfBuffer = reinterpret_cast( + reinterpret_cast( format4 ) + format4->length ); + + const DWORD segCount = format4->segCountX2 / 2; + for( DWORD i = 0; i < segCount; ++i ) + { + swap( static_cast( endCount[i] ) ); + swap( static_cast( startCount[i] ) ); + swap( static_cast( idDelta[i] ) ); + swap( static_cast( idRangeOffset[i] ) ); + } + + USHORT *glyphId = const_cast( &idRangeOffset[segCount] ); + while( glyphId < endOfBuffer ) + { + swap( *glyphId++ ); + } + } + + + bool CharacterMap::getEncoding( CMapEncoding *encoding, int index ) const + { + DWORD result = GetFontData( hdc, cmapName, + cmapHeaderSize + encodingSize * index, + encoding, sizeof( CMapEncoding ) ); + if ( result != sizeof( CMapEncoding ) ) return false; + + swap( encoding->PlatformId ); + swap( encoding->EncodingId ); + swap( encoding->Offset ); + + return true; + } + + bool CharacterMap::getFormat4Header( CMap4 *header, DWORD offset ) const + { + DWORD written = GetFontData( hdc, cmapName, offset, header, format4HeaderSize ); + if ( written != format4HeaderSize ) return false; + + USHORT *fields = reinterpret_cast( header ); + for( int i = 0; i < 7; ++i ) + { + swap( fields[i] ); + } + return true; + } + + + bool CharacterMap::getFormat4Subtable( CMap4 *subtable, DWORD offset ) const + { + if ( !getFormat4Header( subtable, offset ) ) return false; + + const DWORD length = subtable->length - format4HeaderSize; + DWORD written = GetFontData( hdc, cmapName, offset + format4HeaderSize, + subtable->Arrays, length ); + + if ( written != length ) return false; + + swapArrays( subtable ); + + return true; + } + + + unsigned int CharacterMap::getCharacterCount( const CMap4 *format4 ) + { + if ( format4 == NULL ) return 0; + + const USHORT *endCount = getEndCountArray( format4 ); + const USHORT *startCount = getStartCountArray( format4 ); + const USHORT *idRangeOffset = getIdRangeOffsetArray( format4 ); + const USHORT segCount = format4->segCountX2 / 2; + + unsigned int numberOfGlyphs = 0; + + // by adding up the coverage of each segment + for ( USHORT i = 0; i < segCount; ++i ) + { + if ( idRangeOffset[i] == 0 ) + { + // if per the TT spec, the idRangeOffset element is zero, + // all of the characters in this segment exist. + numberOfGlyphs += endCount[i] - startCount[i] + 1; + continue; + } + + const USHORT *glyphId = &(idRangeOffset[i]) + idRangeOffset[i] / 2; + + for (USHORT ch = startCount[i]; ch <= endCount[i]; ++ch ) + { + USHORT idResult = glyphId[ch - startCount[i]]; + if (idResult != 0) numberOfGlyphs++; + } + } + return numberOfGlyphs; + } + + bool CharacterMap::fetchUnicodeCMapTable( void ) + { + USHORT numberOfEncodings; + // Get the number of subtables in the CMAP table from the CMAP header + // The # of subtables is the second USHORT in the CMAP table, per the TT Spec. + DWORD written = GetFontData( hdc, cmapName, sizeof( USHORT ), &numberOfEncodings, sizeof( USHORT ) ); + if ( written != sizeof( USHORT ) ) + { + // Something is wrong, we probably got GDI_ERROR back + // Probably this means that the Device Context does not have + // a TrueType font selected into it. + return false; + } + swap( numberOfEncodings ); + + CMapEncoding encoding = {}; // The current encoding + + // Get the encodings and look for a Unicode Encoding + DWORD iUnicode = numberOfEncodings; + for ( DWORD i = 0; i < numberOfEncodings; ++i ) + { + if ( !getEncoding( &encoding, i ) ) return false; + + if (encoding.PlatformId == 3 && + (encoding.EncodingId == 1 || encoding.EncodingId == 0) ) + { + iUnicode = i; // Set the index to the Unicode encoding + } + } + + // index out of range means failure to find a Unicode mapping + if ( iUnicode >= numberOfEncodings ) + { + // No Unicode encoding found. + return false; + } + + CMap4 format4; // Unicode subtable format + // Get the header entries(first 7 USHORTs) for the Unicode encoding. + if ( !getFormat4Header( &format4, encoding.Offset ) ) + { + return false; + } + + if ( format4.format != 4 ) + { + // Windows7‚Ì"‚l‚r –¾’©"“™‚Íformat4.format‚ª12 + return false; + } + + delete [] cmapTable; + cmapTable = reinterpret_cast( new unsigned char[format4.length] ); + if ( cmapTable == NULL ) return false; + + if ( !getFormat4Subtable( cmapTable, encoding.Offset )) return false; + + return true; + } + + bool CharacterMap::findFormat4Segment( + CMap4 *table, // a valid Format4 subtable buffer + USHORT ch, // Unicode character to search for + USHORT &index // out: index of segment containing ch + ) const + { + if ( NULL == table ) return FALSE; + + const USHORT segCount = table->segCountX2 / 2; + const USHORT *startCount = getStartCountArray( table ); + const USHORT *endCount = getEndCountArray( table ); + + // Find segment that could contain the Unicode character code + for( USHORT i = 0; i < segCount; ++i ) + { + if ( endCount[i] >= ch ) + { + // character code not within the range of the segment + if ( startCount[i] > ch ) return false; + // this segment contains the character code + index = i; + return true; + } + } + // We looked in them all, ch not there + return false; + } + + + unsigned int CharacterMap::getGlyphIndex( unsigned int character ) + /* + When the TrueType font contains a glyph for ch, the + function returns the glyph index for that character. + + If an error occurs, or there is no glyph for ch, the + function will return the missing glyph index of zero. + */ + { + if ( NULL == cmapTable ) return 0; + + USHORT i; + // Find the cmap segment that has the character code. + if ( !findFormat4Segment( cmapTable, static_cast( character ), i ) ) + { + return 0; // Œ©‚‚©‚ç‚È‚©‚Á‚½ + } + + // Get pointers to the cmap data + + const USHORT *idRangeOffset = getIdRangeOffsetArray( cmapTable ); + const USHORT *idDelta = getIdDeltaArray( cmapTable ); + const USHORT *startCount = getStartCountArray( cmapTable ); + + if ( idRangeOffset[i] == 0 ) // Per TT spec, if the RangeOffset is zero, + { + // calculate the glyph index directly + return static_cast( (idDelta[i] + character) & 0xFFFF ); + } + + const USHORT *glyphId = &idRangeOffset[i] + idRangeOffset[i] / 2; + // otherwise, use the glyph id array to get the index + USHORT idResult = glyphId[character - startCount[i]]; // indexing equation from TT spec + + if ( !idResult ) return 0; // return the missing glyph + // Per TT spec, nonzero means there is a glyph + return (idDelta[i] + idResult) & 0xFFFF; + } + + + /* CMAP table Data + From the TrueType Spec revision 1.66 + + USHORT Table Version # + USHORT Number of encoding tables + */ + const size_t CharacterMap::cmapHeaderSize = sizeof( USHORT ) * 2; + + /* ENCODING entry Data aka CMAPENCODING + From the TrueType Spec revision 1.66 + + USHORT Platform Id + USHORT Platform Specific Encoding Id + ULONG Byte Offset from beginning of table + */ + const size_t CharacterMap::encodingSize = sizeof( USHORT ) * 2 + sizeof( ULONG ); + + const size_t CharacterMap::format4HeaderSize = sizeof( USHORT ) * 7; + + // DWORD packed four letter table name for each GetFontData() + // function call when working with the CMAP TrueType table + const DWORD CharacterMap::cmapName = makeTableName( 'c','m','a','p' ); +} diff --git a/nsdfont/src/CharacterMap.h b/nsdfont/src/CharacterMap.h new file mode 100755 index 0000000..0106e7f --- /dev/null +++ b/nsdfont/src/CharacterMap.h @@ -0,0 +1,129 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#pragma once + +#define NOMINMAX +#include +namespace nsdfont +{ + /** + * TrueTypeƒtƒHƒ“ƒg‚̃e[ƒuƒ‹‚©‚çƒOƒŠƒtƒCƒ“ƒfƒbƒNƒX‚ð’T‚·. + */ + class CharacterMap + { + #pragma pack(1) // for byte alignment + private: + struct CMap4 // From the TrueType Spec. revision 1.66 + { + USHORT format; // Format number is set to 4. + USHORT length; // Length in bytes. + USHORT version; // Version number (starts at 0). + USHORT segCountX2; // 2 x segCount. + USHORT searchRange; // 2 x (2**floor(log2(segCount))) + USHORT entrySelector; // log2(searchRange/2) + USHORT rangeShift; // 2 x segCount - searchRange + + USHORT Arrays[1]; // Placeholder symbol for address of arrays following + }; + + struct CMapEncoding + { + USHORT PlatformId; + USHORT EncodingId; + ULONG Offset; + }; + + private: + HDC hdc; + HFONT hFont; + CMap4 *cmapTable; + unsigned int characterCount; // the number of Unicode character glyphs + static const size_t cmapHeaderSize; + static const size_t encodingSize; + static const size_t format4HeaderSize; + static const DWORD cmapName; + public: + CharacterMap( void ); + ~CharacterMap( void ); + + /** + * ƒOƒŠƒtƒCƒ“ƒfƒbƒNƒX‚ðŽæ“¾. + * @param character ƒOƒŠƒt‚ðŽæ“¾‚·‚镶Žš‚ÌUnicode + * @return ƒOƒŠƒtƒCƒ“ƒfƒbƒNƒX + */ + unsigned int getGlyphIndex( unsigned int character ); + + /** + * ƒtƒHƒ“ƒg‚ð‘I‘ð. + * @param font ƒtƒHƒ“ƒgî•ñ + * @return ¬Œ÷‚Ì‰Â”Û + * @retval true ¬Œ÷ + * @retval false Ž¸”s + */ + bool selectFont( const LOGFONTA *font ); + + + inline HDC getDC( void ){ return hdc; } + private: + void clearFont( void ); + bool fetchUnicodeCMapTable( void ); + bool getEncoding( CMapEncoding *encoding, int index ) const; + bool getFormat4Header( CMap4 *format4, DWORD offset ) const; + bool getFormat4Subtable ( CMap4 *subtable, DWORD offset ) const; + bool findFormat4Segment( CMap4 *table, USHORT ch, USHORT &index ) const; + static unsigned int getCharacterCount( const CMap4 *format4 ); + + inline static DWORD makeTableName( char c1, char c2, char c3, char c4 ) + { + DWORD name = 0; + name |= static_cast( c4 ) << 0x18; + name |= static_cast( c3 ) << 0x10; + name |= static_cast( c2 ) << 0x08; + name |= static_cast( c1 ); + return name; + } + + inline static void swap( USHORT &x ){ x = ((x & 0xFF) << 8) | ((x & 0xFF00) >> 8);} + inline static void swap( ULONG &x ) + { + x = ((x & 0xFF) << 24) | ((x & 0xFF000000) >> 24) | + ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8); + } + + inline static const USHORT *getEndCountArray( const CMap4 *cmap4 ) + { + const USHORT *p = reinterpret_cast( cmap4 ); + return &p[7]; // 7 header + } + + inline static const USHORT *getStartCountArray( const CMap4 *cmap4 ) + { + const DWORD segCount = cmap4->segCountX2 / 2; + const USHORT *p = reinterpret_cast( cmap4 ); + return &p[7 + 1 + segCount * 1]; // 7 header + 1 reserved USHORT + } + + inline static const USHORT *getIdDeltaArray( const CMap4 *cmap4 ) + { + const DWORD segCount = cmap4->segCountX2 / 2; + const USHORT *p = reinterpret_cast( cmap4 ); + return &p[7 + 1 + segCount * 2]; // 7 header + 1 reserved USHORT + } + + inline static const USHORT *getIdRangeOffsetArray( const CMap4 *cmap4 ) + { + const DWORD segCount = cmap4->segCountX2 / 2; + const USHORT *p = reinterpret_cast( cmap4 ); + return &p[7 + 1 + segCount * 3]; // 7 header + 1 reserved USHORT + } + /** + * ƒGƒ“ƒfƒBƒAƒ“•ÏX. + */ + static void swapArrays( CMap4 *format4 ); + }; +} diff --git a/nsdfont/src/Color.h b/nsdfont/src/Color.h new file mode 100755 index 0000000..96fbcc6 --- /dev/null +++ b/nsdfont/src/Color.h @@ -0,0 +1,116 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#pragma once +#include + +namespace nsdfont +{ + struct Color + { + private: + unsigned int argb; + public: + Color( void ) : argb( 0x00000000 ){} + + Color( unsigned int argb ) : + argb( argb ) + { + } + + Color( unsigned int rgb, unsigned int alpha ) + { + setArgb( rgb, alpha ); + } + Color( unsigned int red, unsigned int green, + unsigned int blue, unsigned int alpha ) + { + setArgb( red, green, blue , alpha ); + } + + ~Color(void) {} + + /* + inline Color &operator=( const Color &c ) + { + argb = c.getArgb(); + return *this; + } + */ + + inline unsigned int getArgb( void ) const { return argb; } + inline unsigned int getRgb( void ) const { return argb & 0xFFFFFF; } + inline unsigned int getR( void ) const { return (argb >> 16) & 0xFF; } + inline unsigned int getG( void ) const { return (argb >> 8) & 0xFF; } + inline unsigned int getB( void ) const { return argb & 0xFF; } + inline unsigned int getA( void ) const { return argb >> 24; } + inline void setArgb( unsigned int argb ){ this->argb = argb; } + inline void setArgb( unsigned int rgb, unsigned int alpha ) + { + if ( 0xFF <= alpha ) alpha = 0xFF; + argb = (rgb & 0xFFFFFF) | ( alpha << 24 ); + } + inline void setArgb( unsigned int red, unsigned int green, + unsigned int blue, unsigned int alpha ) + { + argb = blue | (green << 8) | (red << 16) | ( alpha << 24 ); + } + inline void setA( unsigned int alpha ) + { + argb = (argb & 0xFFFFFF) | ( alpha << 24 ); + } + inline void setRgb( unsigned int rgb ) + { + argb = (argb & 0xFF000000) | (rgb & 0xFFFFFF); + } + inline void setRgb( unsigned int red, unsigned int green, unsigned int blue ) + { + argb = (argb & 0xFF000000) | blue | (green << 8) | (red << 16); + } + + /** + * RGBF‹óŠÔ‚©‚çHSVF‹óŠÔ‚É•ÏŠ·‚·‚é. + * @attention HSV‚»‚ꂼ‚ê8bit‚Ì‚½‚ß•ÏŠ·‚ɍۂµî•ñ‚ª—ò‰»‚·‚é. + */ + inline void toHsv( void ) + { + const unsigned int r = getR(); + const unsigned int g = getG(); + const unsigned int b = getB(); + const unsigned int cmax = std::max( r, std::max( g, b ) ); + const unsigned int cmin = std::min( r, std::min( g, b ) ); + const unsigned int delta = cmax - cmin; + const unsigned int s = (cmax == 0) ? 0 : (255 * delta) / cmax; + if ( s == 0 ) + { + argb = (argb & 0xFF000000) | cmax; + return; + } + if ( r == cmax ) + { + // 2796203 = (256 << 16) / 6 + setRgb( 2796203 * (g - b) / (delta << 16), s, cmax ); + } + else if ( g == cmax ) + { + // 5592405 = (256 << 16) / 3 + setRgb( (2796203 * (b - r) + 5592405) / (delta << 16), s, cmax ); + } + else if ( b == cmax ) + { + // 11184811 = (256 << 16) * 2 / 3 + setRgb( (2796203 * (r - g) + 11184811) / (delta << 16), s, cmax ); + } + } + + inline void toRgb( void ) + { + + } + + }; +} diff --git a/nsdfont/src/ColorBlender.cpp b/nsdfont/src/ColorBlender.cpp new file mode 100755 index 0000000..6926ce1 --- /dev/null +++ b/nsdfont/src/ColorBlender.cpp @@ -0,0 +1,51 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#include "ColorBlender.h" + +namespace nsdfont +{ + ColorBlender::ColorBlender( void ) + { + } + + ColorBlender::~ColorBlender( void ) + { + } + + ColorBlender::MulTable::MulTable( void ) + { + size_t i = 0; + for( int y = 0; y < 256; ++y ) + { + int acc = 0; + for(;;) + { + table[i++] = static_cast( (acc + 255) / 510 ); + if ( (i & 0xFF) == 0 ) break; + acc += y + y; + } + } + } + + ColorBlender::DivTable::DivTable( void ) + { + size_t i = 0x100; + for( int divider = 1; divider < 256; ++divider ) + { + const int divider2 = divider << 1; + for( int x = 0; x < 256 * 510; x += 510 ) + { + // x <= divider2 ‚ŃI[ƒo[ƒtƒ[ + table[i++] = static_cast( (x + divider) / divider2 ); + } + } + } + + const ColorBlender::MulTable ColorBlender::mulTable; + const ColorBlender::DivTable ColorBlender::divTable; +} \ No newline at end of file diff --git a/nsdfont/src/ColorBlender.h b/nsdfont/src/ColorBlender.h new file mode 100755 index 0000000..cd68b6b --- /dev/null +++ b/nsdfont/src/ColorBlender.h @@ -0,0 +1,135 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#pragma once +#include "Color.h" + +namespace nsdfont +{ + class ColorBlender + { + private: + class Table + { + protected: + unsigned char table[256*256]; + public: + inline unsigned int operator[]( size_t i ) const + { + return static_cast( table[i] ); + } + }; + + /** + * æŽZƒe[ƒuƒ‹. + */ + class MulTable : public Table + { + public: + MulTable(); + }; + /** + * œŽZƒe[ƒuƒ‹. + */ + class DivTable : public Table + { + public: + DivTable(); + }; + + static const MulTable mulTable; + static const DivTable divTable; + public: + ColorBlender( void ); + + ~ColorBlender( void ); + + /** + * æŽZ + */ + static inline unsigned int mul( const unsigned int v1, const unsigned int v2 ) + { + const size_t i = v1 + (v2 << 8); + return mulTable[i]; + } + + /** + * ƒXƒNƒŠ[ƒ“(”½“]æŽZ) + */ + static inline unsigned int scr( const unsigned int v1, const unsigned int v2 ) + { + const size_t i = (v1 + (v2 << 8)) ^ 0xFFFF; + return mulTable[i] ^ 0xFF; + } + + static inline unsigned int div( const unsigned int numerator, const unsigned int divider ) + { + const size_t i = numerator + (divider << 8); + return divTable[i]; + } + + static inline Color blend( const Color &c1, const Color &c2, unsigned int rate ) + { + const unsigned int inv = 255 - rate; + const unsigned int newA = mul( c1.getA(), inv ) + mul( c2.getA(), rate ); + const unsigned int newR = mul( c1.getR(), inv ) + mul( c2.getR(), rate ); + const unsigned int newG = mul( c1.getG(), inv ) + mul( c2.getG(), rate ); + const unsigned int newB = mul( c1.getB(), inv ) + mul( c2.getB(), rate ); + return Color( newR, newG, newB, newA ); + } + + static inline Color interpolate( const Color &c1, const Color &c2, double rate ) + { + const unsigned int r = static_cast( 255 * rate ); + return blend( c1, c2, r ); + } + + static inline Color interpolateHsv( const Color &c1, const Color &c2, double rate ) + { + const unsigned int r = static_cast( 255 * rate ); + return blend( c1, c2, r ); + } + + + /** + * 2‚‚̐F‚ðd‚ˍ‡‚킹‚½F‚𐶐¬‚·‚é. + * @param back ‰º‘w‚̐F + * @param fore ‘O–ʂ̐F + * @return d‚ˍ‡‚킹‚½F + */ + static inline Color merge( const Color &back, const Color &fore ) + { + // C = blend( blend( C0, C1, A1), C2, A2 ) + // = blend( C0*(1-A1) + C1*A1, C2, A2 ) + // = C0*(1-A1)*(1-A2) + C1*A1*(1-A2) + C2*A2 + // = blend( C0, {C1*A1*(1-A2) + C2*A2}/{1-(1-A1)*(1-A2)}, 1-(1-A1)*(1-A2) ) + // = blend( C0, {C1*A1 + C2*A2 - C1*A1*A2}/scr(A1,A2), scr(A1,A2) ) + const unsigned int backA = back.getA(); + if ( backA == 0 ) return Color( fore ); + const unsigned int foreA = fore.getA(); + if ( foreA == 0 ) return Color( back ); + const unsigned int mulA = mul( backA, foreA ); + + const unsigned int backR = back.getR(); + const unsigned int foreR = fore.getR(); + const unsigned int newR = mul( backR, backA ) + mul( foreR, foreA ) + - mul( backR, mulA ); + const unsigned int backG = back.getG(); + const unsigned int foreG = fore.getG(); + const unsigned int newG = mul( backG, backA ) + mul( foreG, foreA ) + - mul( backG, mulA ); + const unsigned int backB = back.getB(); + const unsigned int foreB = fore.getB(); + const unsigned int newB = mul( backB, backA ) + mul( foreB, foreA ) + -mul( backB, mulA ); + const unsigned int newA = scr( backA, foreA ); + return Color( div( newR, newA ), + div( newG, newA ), + div( newB, newA ), newA ); + } + }; +} \ No newline at end of file diff --git a/nsdfont/src/Decorator.cpp b/nsdfont/src/Decorator.cpp new file mode 100755 index 0000000..fff1586 --- /dev/null +++ b/nsdfont/src/Decorator.cpp @@ -0,0 +1,180 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#include "Decorator.h" +#include + +namespace nsdfont +{ + Decorator::Decorator( void ) + { + face1 = Color( 0xFFFFFFFF ); + } + + Decorator::~Decorator( void ) + { + } + + void Decorator::setFace( const Color color ) + { + face1 = color; + face2 = color; + } + + void Decorator::setEdge( const double width, const Color color ) + { + // + // : + // l : l l2,2l + // +-+-+---+---+ + // l : l1,1l2,1l + // +-+-+---+---+---+ + // --+0,0+1,0+2,0+3,0+----> + // +-:-+---+---+---+ + // | : l l l | + // : + + // ƒe[ƒuƒ‹‰Šú‰» + // ³•ûŒ`‚Å‚ ‚邱‚Æ‚ð‘O’ñ + const size_t tableSize = sizeof( edgePower ) / sizeof( edgePower[0] ); + for( size_t j = 0; j < tableSize; ++j ) + { + for( size_t i = 0; i < tableSize; ++i ) + { + edgePower[j][i] = 0; + } + } + + if ( width <= 1e-20 ) + { + edgeWidth = 0.0; + return; + } + + edge1 = color; + exTop = exBottom = exLeft = exRight = static_cast( std::ceil( edgeWidth ) ); + + const double r = width + rEqu; // ‰~‚Ì”¼Œa + const double s = rPi * r * r; // ‰~‚Ì–ÊÏ + const double scale( edge1.getA() ); + if ( r <= rSqrt0_5 ) // (0.5,0.5)“ž’B‚Ü‚Å + { + // a0 = SQRT(r^2-0.5^2) * 2 + 2*r^2*( + // ASIN(0.5/r)-ACOS(0.5/r) + // + 0.5*SIN(2*ASIN(0.5/r))-0.5*SIN(2*ACOS(0.5/r)) + // ) + const double a0 = 1.0 - 4.333 * (r - rSqrt0_5) * (r - rSqrt0_5); //2ŽŸ‹ßŽ— + const double a1 = 0.25 * (s - a0); + edgePower[0][0] = static_cast( a0 * scale ); + edgePower[1][0] = static_cast( a1 * scale ); + edgePower[1][1] = 0; + return; + } + if ( r <= 1.5 ) // (1.5,0.0)“ž’B‚Ü‚Å + { + // b0 = 0.5*SQRT(r^2-0.5^2)-0.5+r^2*ASIN(0.5/r) + + const double b0 = 1.0422359371 * r - 0.5878914747; //1ŽŸ‹ßŽ— + const double b1 = 0.25 * (s - 1.0) - b0; + edgePower[0][0] = static_cast( scale ); + edgePower[1][0] = static_cast( b0 * scale ); + edgePower[1][1] = static_cast( b1 * scale ); + return; + } + + } + + void Decorator::drawFace( int x, int y, ArgbBitmap &bmp, const Glyph &glyph ) const + { + if ( glyph.getBufferSize() <= 0 ) return; + + drawCoreSimple( x, y, bmp, glyph, face1 ); + } + + void Decorator::drawCoreSimple( int x, int y, ArgbBitmap &bmp, const Glyph &glyph, const Color color ) const + { + // Š®‘S‚É“§–¾‚È‚ç•`‰æ‚µ‚È‚¢ + if ( color.getA() == 0 ) return; + + x += exLeft; + y += exTop; + + int width, height; + unsigned char *src = clip( x, y, width, height, bmp, glyph ); + + for( int j = 0; j < height; ++j ) + { + ArgbArray dest = bmp.getArray( x, y + j ); + for( int i = 0; i < width; ++i ) + { + if ( src[i] == 0 ) continue; + const Color face( color.getArgb(), blend.mul( color.getA(), src[i] ) ); + dest[i] = blend.merge( dest[i], face ); + } + src += glyph.getPitch(); + } + } + + void Decorator::drawEdge( int x, int y, ArgbBitmap &bmp, const Glyph &glyph ) const + { + if ( glyph.getBufferSize() <= 0 ) return; + + const Color c00( edge1.getArgb(), edgePower[0][0] ); + const Color c10( edge1.getArgb(), edgePower[1][0] ); + const Color c11( edge1.getArgb(), edgePower[1][1] ); + + drawCoreSimple( x-1, y-1, bmp, glyph, c11 ); // ¶ã + drawCoreSimple( x+0, y-1, bmp, glyph, c10 ); // ’†ã + drawCoreSimple( x+1, y-1, bmp, glyph, c11 ); // ‰Eã + drawCoreSimple( x-1, y+0, bmp, glyph, c10 ); // ¶’† + drawCoreSimple( x+0, y+0, bmp, glyph, c00 ); // ’†’† + drawCoreSimple( x+1, y+0, bmp, glyph, c10 ); // ‰E’† + drawCoreSimple( x-1, y+1, bmp, glyph, c11 ); // ¶‰º + drawCoreSimple( x+0, y+1, bmp, glyph, c10 ); // ’†‰º + drawCoreSimple( x+1, y+1, bmp, glyph, c11 ); // ‰E‰º + if ( edgePower[2][0] > 0 ) + { + + } + return; + } + + unsigned char *Decorator::clip( int &x, int &y, int &width, int &height, + const ArgbBitmap &bmp, const Glyph&glyph ) const + { + width = glyph.getWidth(); + height = glyph.getHeight(); + unsigned char *src = glyph.getBuffer(); + + if ( x < 0 ) //(¶‚ɂ͂ݏo‚Ä‚¢‚é) + { + width += x; + src -= x; + x = 0; + } + if ( y < 0 ) //(ã‚ɂ͂ݏo‚Ä‚¢‚é) + { + height += y; + src -= y * glyph.getPitch(); + y = 0; + } + if ( x + width > bmp.getWidth() ) //(‰E‚ɂ͂ݏo‚Ä‚¢‚é) + { + width = bmp.getWidth() - x; + } + if ( y + height > bmp.getHeight() ) //(‰º‚ɂ͂ݏo‚Ä‚¢‚é) + { + height = bmp.getHeight() - y; + } + return src; + } + + + const double Decorator::rPi( 3.14159265358979323846 ); // pi + const double Decorator::rEqu( 0.564189583547756286948 ); // sqrt( 1 / pi ) + const double Decorator::rSqrt0_5( 0.7071067811865475244 ); // sqrt( 0.5 ) +} diff --git a/nsdfont/src/Decorator.h b/nsdfont/src/Decorator.h new file mode 100755 index 0000000..d822958 --- /dev/null +++ b/nsdfont/src/Decorator.h @@ -0,0 +1,59 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#pragma once +#include "ArgbBitmap.h" +#include "ColorBlender.h" +#include "Glyph.h" + +namespace nsdfont +{ + /** + * ‘•ü‚ðŽ{‚µ‚ăOƒŠƒt‚ð•`‰æ‚·‚é. + */ + class Decorator + { + private: + const ColorBlender blend; + static const double rPi; // pi + static const double rEqu; // sqrt( 1 / pi ) + static const double rSqrt0_5; // sqrt( 0.5 ) + mutable Color face1; + Color face2; + Color edge1; + Color edge2; + double edgeWidth; + static const size_t maxRadius; + int edgePower[4][4]; + int exLeft; + int exTop; + int exRight; + int exBottom; + public: + Decorator( void ); + ~Decorator( void ); + Decorator &operator=( const Decorator &d ); + void setFace( const Color color ); + void setEdge( const double width, const Color color ); + void drawEdge( int x, int y, ArgbBitmap &bmp, const Glyph &glyph ) const; + void drawFace( int x, int y, ArgbBitmap &bmp, const Glyph &glyph ) const; + inline void getExtensionSize( int &left, int &top, int &right, int &bottom ) const + { + left = exLeft; + top = exTop; + right = exRight; + bottom = exBottom; + } + private: + void drawCoreSimple( int x, int y, ArgbBitmap &bmp, const Glyph &glyph, const Color color ) const; + void drawEdge1( int x, int y, ArgbBitmap &bmp, const Glyph &glyph ) const; + void drawEdge2( int x, int y, ArgbBitmap &bmp, const Glyph &glyph ) const; + unsigned char *clip( int &x, int &y, int &width, int &height, + const ArgbBitmap &bmp, const Glyph&glyph ) const; + }; +} + diff --git a/nsdfont/src/Glyph.cpp b/nsdfont/src/Glyph.cpp new file mode 100755 index 0000000..0686456 --- /dev/null +++ b/nsdfont/src/Glyph.cpp @@ -0,0 +1,225 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#include "Glyph.h" +#include + +namespace nsdfont +{ +#undef GetGlyphOutline + + Glyph::Glyph( void ) + { + bufferSize = 0; + buffer = NULL; + } + + Glyph::Glyph( const Glyph& glyph ) + { + character = glyph.character; + memcpy( &metrics, &glyph.metrics, sizeof( metrics ) ); + bufferSize = glyph.bufferSize; + if ( bufferSize > 0 ) + { + buffer = new unsigned char[bufferSize]; + memcpy( buffer, glyph.buffer, bufferSize ); + } + else + { + buffer = NULL; + } + } + + Glyph::Glyph( unsigned int character ) + { + bufferSize = 0; + buffer = NULL; + this->character = character; + const unsigned int index = + ( mode & GGO_GLYPH_INDEX ) ? cm.getGlyphIndex( character ) : character; + + // •K—vƒoƒbƒtƒ@ƒTƒCƒYCƒƒgƒŠƒNƒXŽæ“¾(lpvBuffer=NULL) + const DWORD bufferRequest = GetGlyphOutline( cm.getDC(), index, mode, &metrics, 0, NULL, &transform ); + if ( bufferRequest == GDI_ERROR ) return; + + if ( bufferRequest == 0 ) + { + // GetGlyphOutline‚̃oƒO‚É‚æ‚è0‚É‚È‚ç‚È‚¢ê‡‚ª‚ ‚é + metrics.gmBlackBoxX = 0; + metrics.gmBlackBoxY = 0; + return; + } + // GetGlyphOutline‚Ì•Ô‚·ƒoƒbƒtƒ@ƒTƒCƒY‚͐M—p‚µ‚Ä‚Í‚¢‚¯‚È‚¢‚炵‚¢ + // ‚䂦‚ɃƒgƒŠƒNƒX‚©‚çŒvŽZ‚µ‚½’l‚Æ”äŠr‚µ‚Ä‘å‚«‚¢‚Ù‚¤‚ðÌ—p + bufferSize = static_cast( getHeight() * getPitch() ); + if ( bufferSize < bufferRequest ) bufferSize = bufferRequest; + + buffer = new unsigned char[bufferSize]; + GetGlyphOutline( cm.getDC(), index, mode, &metrics, bufferSize, buffer, &transform ); + + switch( mode & ~GGO_GLYPH_INDEX ) + { + case GGO_GRAY4_BITMAP: + for( size_t i = 0; i < bufferSize; ++i ) + { + const int alpha = (255 * buffer[i]) >> 4; // 0~16 -> 0~255 + buffer[i] = static_cast( alpha ); + } + break; + case GGO_GRAY8_BITMAP: + for( size_t i = 0; i < bufferSize; ++i ) + { + const int alpha = (255 * buffer[i]) >> 6; // 0~64 -> 0~255 + buffer[i] = static_cast( alpha ); + } + break; + default: + break; + } + } + + Glyph::~Glyph(void) + { + if ( NULL != buffer ) + { + delete [] buffer; + } + } + + void Glyph::setFont( const LOGFONTA *font ) + { + cm.selectFont( font ); + GetTextMetrics( cm.getDC(), &textMetrics ); + cache.flush(); + } + + void Glyph::setTransformation( double xScale, double xAngle, double yAngle ) + { + const double deg2rad = 0.0174532925199432957692369; // pi / 180 + xAngle *= deg2rad; + yAngle *= deg2rad; + // ‚±‚Ì•ÏŠ·s—ñ‚͉¡ƒxƒNƒgƒ‹‚ɑ΂·‚é‚à‚̂炵‚¢ + const double m11 = xScale * std::cos( yAngle ); + const double m21 = xScale * std::sin( xAngle ); + const double m12 = -std::sin( yAngle ); + const double m22 = std::cos( xAngle ); + doubleToFixed( m11, transform.eM11 ); + doubleToFixed( m12, transform.eM12 ); + doubleToFixed( m21, transform.eM21 ); + doubleToFixed( m22, transform.eM22 ); + } + + void Glyph::doubleToFixed( double d, FIXED &f ) + { + int i = static_cast( 0x10000 * d ); + f.fract = static_cast( i & 0xFFFF ); + f.value = static_cast( i >> 16 ); + } + + UINT Glyph::detectMode( void ) + { + HMODULE hGdi = GetModuleHandleA( "gdi32.dll" ); + GetGlyphOutline = reinterpret_cast( GetProcAddress( hGdi, "GetGlyphOutlineW" ) ); + // GetGlyphOutline = NULL; + if ( GetGlyphOutline ) + { + return GGO_GRAY8_BITMAP; + } + GetGlyphOutline = reinterpret_cast( GetGlyphOutlineA ); + return GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP; + } + + + const Glyph *Glyph::get( unsigned int character ) + { + return cache.fetch( character ); + } + + // ------------------------------------------------------------------------ + + Glyph::Cache::Cache( size_t capacity ) + { + this->capacity = capacity; + allocated = 0; + } + + Glyph::Cache::~Cache( void ) + { + flush(); + } + + const Glyph *Glyph::Cache::fetch( unsigned int character ) + { + if ( glyphs.count( character ) <= 0 ) + { + add( character ); // ‘¶Ý‚µ‚È‚¯‚ê‚ΒljÁ + } + else + { + // æ“ª‚Ɉړ® + order.remove( character ); // ˆê’Uíœ + order.push_front( character ); // æ“ª‚ɍđ}“ü + } + return glyphs[character]; + } + + void Glyph::Cache::add( unsigned int character ) + { + remove( character ); // ”O‚Ì‚½‚ߊù‘¶ƒf[ƒ^‚ðíœ + reduce(); // ’ljÁ‚·‚éƒOƒŠƒt‚ðÁ‚³‚È‚¢‚½‚߂ɐæ‚ÉŽÀs + const Glyph *g = new Glyph( character ); + glyphs[character] = g; + allocated += g->getBufferSize(); + order.push_front( character ); + } + + void Glyph::Cache::remove( unsigned int character ) + { + if ( glyphs.count( character ) > 0 ) // character‚ª‘¶Ý‚·‚é‚© + { + const Glyph *g = glyphs[character]; + allocated -= g->getBufferSize(); + delete g; + glyphs.erase( character ); + order.remove( character ); + } + } + + void Glyph::Cache::reduce() + { + while( allocated > capacity ) + { + const unsigned int &character = order.back(); // ÅŒã‚Ìfetch‚©‚çˆê”ÔŽžŠÔ‚ª‚½‚Á‚½•¶Žš + const Glyph *g = glyphs[character]; + allocated -= g->getBufferSize(); + delete g; + glyphs.erase( character ); + order.pop_back(); + } + } + + void Glyph::Cache::flush( void ) + { + std::map::iterator it; + for( it = glyphs.begin(); it != glyphs.end(); ++it ) + { + delete (*it).second; + } + glyphs.clear(); + order.clear(); + } + + + + Glyph::GetGlyphOutlinePtr Glyph::GetGlyphOutline = NULL; + const UINT Glyph::mode = Glyph::detectMode(); + CharacterMap Glyph::cm; + TEXTMETRICA Glyph::textMetrics; + Glyph::Cache Glyph::cache( 1024 * 256 ); + MAT2 Glyph::transform = {{1,0}, {0,0}, {0,0}, {0,1}}; +} + diff --git a/nsdfont/src/Glyph.h b/nsdfont/src/Glyph.h new file mode 100755 index 0000000..b1b7e71 --- /dev/null +++ b/nsdfont/src/Glyph.h @@ -0,0 +1,115 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#pragma once +#define NOMINMAX +#include +#include "CharacterMap.h" +#include +#include + +namespace nsdfont +{ + class Glyph + { + private: + class Cache + { + private: + size_t capacity; + size_t allocated; + std::map glyphs; + std::list order; + public: + Cache( size_t capacity ); + ~Cache( void ); + const Glyph *fetch( unsigned int character ); + void add( unsigned int character ); + void remove( unsigned int character ); + void flush( void ); ///< ƒOƒŠƒtƒLƒƒƒbƒVƒ…‚ð‚·‚×‚Äíœ‚·‚é. + void reduce( void ); ///< Žw’èƒTƒCƒY‘Š“–‚ÉŽû‚Ü‚é‚Ü‚ÅŽg‚í‚ê‚Ä‚¢‚È‚¢ƒOƒŠƒt‚ðƒLƒƒƒbƒVƒ…‚©‚çíœ + private: + }; + private: +#undef GetGlyphOutline + typedef DWORD (WINAPI *GetGlyphOutlinePtr)( __in HDC hdc, + __in UINT uChar, + __in UINT fuFormat, + __out LPGLYPHMETRICS lpgm, + __in DWORD cjBuffer, + __out_bcount_opt(cjBuffer) LPVOID pvBuffer, + __in CONST MAT2 *lpmat2 + ); + static GetGlyphOutlinePtr GetGlyphOutline; + unsigned int character; ///< •¶ŽšƒR[ƒh(Unicode) + GLYPHMETRICS metrics; + size_t bufferSize; ///< ƒOƒŠƒtƒrƒbƒgƒ}ƒbƒv‚̃TƒCƒY + unsigned char *buffer; ///< ƒOƒŠƒtƒrƒbƒgƒ}ƒbƒv‚ւ̃|ƒCƒ“ƒ^ + static const UINT mode; + static CharacterMap cm; + static TEXTMETRICA textMetrics; + static MAT2 transform; + static Cache cache; + + public: + Glyph( void ); + Glyph( const Glyph &glyph ); + ~Glyph( void ); + + /** + * Žw’肵‚½•¶Žš‚̃OƒŠƒt‚ðŽæ“¾. + * @param Žæ“¾‚·‚镶Žš(Unicode) + * @return Žæ“¾‚µ‚½ƒOƒŠƒt + * @attention GlyphƒNƒ‰ƒX‚ɑ΂µ‰½‚ç‚©‚Ì‘€ì‚ðs‚¤‚ƁCŽæ“¾‚µ‚½ƒOƒŠƒt‚Í–³Œø‚É‚È‚é‰Â”\«‚ª‚ ‚é. + * ’·Šú“I‚ÉŽg‚¤ê‡‚́C‚Ü‚¸•¡»‚µC•¡»‚µ‚½‚à‚Ì‚ðŽg‚¤‚±‚Æ. + * ‚Ü‚½CŽæ“¾‚µ‚½ƒOƒŠƒt‚Í“à•”‚ÅŠÇ—‚³‚ê‚Ä‚¢‚邽‚߁Cdelete‚µ‚Ä‚Í‚È‚ç‚È‚¢. + */ + static const Glyph *get( unsigned int character ); + + inline int getX( void ) const ///<ƒOƒŠƒt‚Ìx•ûŒü‚ÌŠî“_‚ðŽæ“¾ + { + return static_cast( metrics.gmptGlyphOrigin.x ); + } + inline int getY( void ) const ///<ƒOƒŠƒt‚Ìy•ûŒü‚ÌŠî“_‚ðŽæ“¾ + { + return static_cast( metrics.gmptGlyphOrigin.y ); + } + inline int getWidth( void ) const + { + return static_cast( metrics.gmBlackBoxX ); + } + inline int getHeight( void ) const + { + return static_cast( metrics.gmBlackBoxY ); + } + inline int getPitch( void ) const + { + return (getWidth() + 3) & -4; + } + inline int getCellWidth( void ) const + { + return static_cast( metrics.gmCellIncX ); + } + inline int getAscent( void ) const + { + return static_cast( textMetrics.tmAscent ); + } + inline int getDescent( void ) const + { + return static_cast( textMetrics.tmDescent ); + } + inline unsigned char *getBuffer( void ) const{ return buffer; } + inline size_t getBufferSize( void ) const{ return bufferSize; } + static void setFont( const LOGFONTA *font ); + static void setTransformation( double xScale, double xAngle = 0.0, double yAngle = 0.0 ); + private: + Glyph( unsigned int character ); + Glyph operator=(const Glyph&); // ‘ã“ü‹ÖŽ~ + static UINT detectMode( void ); + static void doubleToFixed( double d, FIXED &f ); + }; +} diff --git a/nsdfont/src/Typesetter.cpp b/nsdfont/src/Typesetter.cpp new file mode 100755 index 0000000..c6bcba5 --- /dev/null +++ b/nsdfont/src/Typesetter.cpp @@ -0,0 +1,88 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#include "Typesetter.h" + +namespace nsdfont +{ + Typesetter::Typesetter( void ) + { + } + + Typesetter::~Typesetter( void ) + { + } + + void Typesetter::setSpace( int horizontal, int vertical ) + { + hSpace = horizontal; + vSpace = vertical; + } + + void Typesetter::calculateRect( int &width, int &height, + UnicodeString &str, const Decorator &decorator ) const + { + str.rewind(); + width = 0; + height = 0; + int x = 0; + int y = 0; + int lineHeight = 0; // Œ»Ý‘ΏۂƂµ‚Ä‚¢‚és‚̍‚‚³ + while( const unsigned int unicode = str.peek() ) + { + const Glyph &glyph = *Glyph::get( unicode ); + if ( '\n' == unicode ) // ‰üs + { + if ( x > hSpace ) x -= hSpace; + if ( x > width ) width = x; + x = 0; + y += glyph.getAscent() + glyph.getDescent(); //1•¶Žš‚̍‚‚³•ª‰º‚Ɉړ® + y += vSpace; // sŠÔ•ªˆÚ“® + lineHeight = 0; + continue; + } + const int bottom = glyph.getAscent() - glyph.getY() + glyph.getHeight(); + if ( bottom > lineHeight ) lineHeight = bottom; + x += glyph.getCellWidth(); + x += hSpace; + } + if ( x > hSpace ) x -= hSpace; + if ( x > width ) width = x; + height = y + lineHeight; + + int exTop,exLeft,exBottom,exRight; + decorator.getExtensionSize( exLeft, exTop, exRight, exBottom ); + width += exLeft + exRight; + height+= exTop + exBottom; + } + + void Typesetter::draw( ArgbBitmap &bmp, UnicodeString &str, const Decorator &decorator ) const + { + str.rewind(); + int x = 0; + int y = 0; + while( const unsigned int unicode = str.peek() ) + { + const Glyph &glyph = *Glyph::get( unicode ); + if ( '\n' == unicode ) + { + x = 0; + y += glyph.getAscent() + glyph.getDescent(); + y += vSpace; + continue; + } + const int gx = glyph.getX(); + const int gy = glyph.getAscent()-glyph.getY(); + + decorator.drawEdge( x + gx, y + gy, bmp, glyph ); + decorator.drawFace( x + gx, y + gy, bmp, glyph ); + + x += glyph.getCellWidth(); + x += hSpace; + } + } +} \ No newline at end of file diff --git a/nsdfont/src/Typesetter.h b/nsdfont/src/Typesetter.h new file mode 100755 index 0000000..dd10760 --- /dev/null +++ b/nsdfont/src/Typesetter.h @@ -0,0 +1,29 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#pragma once + +#include "UnicodeString.h" +#include "ArgbBitmap.h" +#include "Decorator.h" + +namespace nsdfont +{ + class Typesetter + { + private: + int hSpace; + int vSpace; + public: + Typesetter( void) ; + ~Typesetter( void ); + void setSpace( int horizonal, int vertical ); + void calculateRect( int &width, int &height, + UnicodeString &str, const Decorator &decorator ) const; + void draw( ArgbBitmap &bmp, UnicodeString &str, const Decorator &decorator ) const; + }; +} diff --git a/nsdfont/src/UnicodeString.cpp b/nsdfont/src/UnicodeString.cpp new file mode 100755 index 0000000..8c7d289 --- /dev/null +++ b/nsdfont/src/UnicodeString.cpp @@ -0,0 +1,340 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#include "UnicodeString.h" + +namespace nsdfont +{ + UnicodeString::UnicodeString( Codepage codepage, const char *str, size_t length ) + { + this->length = MultiByteToWideChar( codepage, MB_PRECOMPOSED, str, length, NULL, 0 ); + unicodeStr = new wchar_t[this->length]; + this->length = MultiByteToWideChar( codepage, MB_PRECOMPOSED, str, length, unicodeStr, this->length ); + position = 0; + } + + UnicodeString::~UnicodeString( void ) + { + delete[] unicodeStr; + } + + unsigned int UnicodeString::peek( void ) + { + if ( position >= length ) return 0; + + wchar_t character = unicodeStr[position++]; + if ( character == L'&' ) + { + if ( position >= length ) return L'&'; + character = unicodeStr[position]; + if ( character == L'#' ) + { + return parseNumericEntity(); + } + return parseCharacterEntity(); + } + return character; + } + + unsigned int UnicodeString::parseNumericEntity( void ) + { + if ( (position + 1) >= length ) return L'&'; + position++; + wchar_t code = 0; + if ( unicodeStr[position] == L'x' ) //16i” + { + position++; + while( position < length ) + { + const wchar_t w = unicodeStr[position++]; + if ( L'0' <= w && w <= L'9' ) + { + code = (code << 4) + w - L'0'; + } + else if ( L'A' <= w && w <= L'F' ) + { + code = (code << 4) + w - L'A' + 10; + } + else if ( L'a' <= w && w <= L'f' ) + { + code = (code << 4) + w - L'a' + 10; + } + else + { + break; + } + } + return code; + } + + while( position < length ) + { + const wchar_t w = unicodeStr[position++]; + if ( L'0' <= w && w <= L'9' ) + { + code = code * 10 + w - L'0'; + } + else + { + break; + } + + } + return code; + } + + unsigned int UnicodeString::parseCharacterEntity( void ) + { + char c[10]; + size_t len = 0; + size_t limit = length - position; + if ( limit > 10 ) limit = 10; + for( size_t i = 0; i < limit; ++i ) + { + len = i; + wchar_t w = unicodeStr[position++]; + if ( w & 0xFF00 ) return L'&'; + if ( w == L';' ) break; + c[i] = static_cast< unsigned char>( w & 0xFF ); + } + // ˆÈ‰ºA•¶Žš”–ˆ‚ɐüŒ`’Tõ + if ( 2 == len ) + { + const int entries = 15; + static const char e2[entries][2] = { + {'l','t'}, {'g','t'}, {'M','u'}, {'N','u'}, + {'X','i'}, {'P','i'}, {'m','u'}, {'n','u'}, + {'x','i'}, {'p','i'}, {'n','i'}, {'o','r'}, + {'n','e'}, {'l','e'}, {'g','e'} + }; + static const wchar_t c2[entries] = { + 0x003C, 0x003E, 0x039C, 0x039D, + 0x039E, 0x03A0, 0x03BC, 0x03BD, + 0x03BE, 0x03C0, 0x220B, 0x2228, + 0x2260, 0x2264, 0x2265 + }; + + for( size_t i = 0; i < entries; ++i ) + { + if ( *reinterpret_cast( c ) == + *reinterpret_cast( e2[i] ) ) + { + return c2[i]; + } + } + } + else if ( 3 == len ) + { + const int entries = 35; + static const char e3[entries][4] = { + {'a','m','p'}, {'y','e','n'}, {'u','m','l'}, {'n','o','t'}, + {'s','h','y'}, {'r','e','g'}, {'d','e','g'}, {'E','T','H'}, + {'e','t','h'}, {'E','t','a'}, {'R','h','o'}, {'T','a','u'}, + {'P','h','i'}, {'C','h','i'}, {'P','s','i'}, {'e','t','a'}, + {'r','h','o'}, {'t','a','u'}, {'p','h','i'}, {'c','h','i'}, + {'p','s','i'}, {'p','i','v'}, {'z','w','j'}, {'l','r','m'}, + {'r','l','m'}, {'s','u','m'}, {'a','n','g'}, {'a','n','d'}, + {'c','a','p'}, {'c','u','p'}, {'i','n','t'}, {'s','i','m'}, + {'s','u','b'}, {'s','u','p'}, {'l','o','z'} + }; + static const wchar_t c3[entries] = { + 0x0026, 0x00A5, 0x00A8, 0x00AC, + 0x00AD, 0x00AE, 0x00B0, 0x00D0, + 0x00F0, 0x0397, 0x03A1, 0x03A4, + 0x03A6, 0x03A7, 0x03A8, 0x03B7, + 0x03C1, 0x03C4, 0x03C6, 0x03C7, + 0x03C8, 0x03D6, 0x200D, 0x200E, + 0x200F, 0x2211, 0x2220, 0x2227, + 0x2229, 0x222A, 0x222B, 0x223C, + 0x2282, 0x2283, 0x25CA + }; + c[3] = 0; + for( size_t i = 0; i < entries; ++i ) + { + if ( *reinterpret_cast( c ) == + *reinterpret_cast( e3[i] ) ) + { + return c3[i]; + } + } + } + else if ( 4 == len ) + { + const int entries = 60; + static const char e4[entries][4] = { + {'q','u','o','t'}, {'n','b','s','p'}, {'c','e','n','t'}, {'s','e','c','t'}, + {'c','o','p','y'}, {'o','r','d','f'}, {'m','a','c','r'}, {'s','u','p','2'}, + {'s','u','p','3'}, {'p','a','r','a'}, {'s','u','p','1'}, {'o','r','d','m'}, + {'A','u','m','l'}, {'E','u','m','l'}, {'I','u','m','l'}, {'O','u','m','l'}, + {'U','u','m','l'}, {'a','u','m','l'}, {'e','u','m','l'}, {'i','u','m','l'}, + {'o','u','m','l'}, {'u','u','m','l'}, {'y','u','m','l'}, {'Y','u','m','l'}, + {'f','n','o','f'}, {'c','i','r','c'}, {'B','e','t','a'}, {'Z','e','t','a'}, + {'I','o','t','a'}, {'b','e','t','a'}, {'z','e','t','a'}, {'i','o','t','a'}, + {'e','n','s','p'}, {'e','m','s','p'}, {'z','w','n','j'}, {'b','u','l','l'}, + {'e','u','r','o'}, {'r','e','a','l'}, {'l','a','r','r'}, {'u','a','r','r'}, + {'r','a','r','r'}, {'d','a','r','r'}, {'h','a','r','r'}, {'l','A','r','r'}, + {'u','A','r','r'}, {'r','A','r','r'}, {'d','A','r','r'}, {'h','A','r','r'}, + {'p','a','r','t'}, {'i','s','i','n'}, {'p','r','o','d'}, {'p','r','o','p'}, + {'c','o','n','g'}, {'n','s','u','b'}, {'s','u','b','e'}, {'s','u','p','e'}, + {'p','e','r','p'}, {'s','d','o','t'}, {'l','a','n','g'}, {'r','a','n','g'} + + }; + static const wchar_t c4[entries] = { + 0x0022, 0x00A0, 0x00A2, 0x00A7, + 0x00A9, 0x00AA, 0x00AF, 0x00B2, + 0x00B3, 0x00B6, 0x00B9, 0x00BA, + 0x00C4, 0x00CB, 0x00CF, 0x00D6, + 0x00DC, 0x00E4, 0x00EB, 0x00EF, + 0x00F6, 0x00FC, 0x00FF, 0x0178, + 0x0192, 0x02C6, 0x0392, 0x0396, + 0x0399, 0x03B2, 0x03B6, 0x03B9, + 0x2002, 0x2003, 0x200C, 0x2022, + 0x20AC, 0x211C, 0x2190, 0x2191, + 0x2192, 0x2193, 0x2194, 0x21D0, + 0x21D1, 0x21D2, 0x21D3, 0x21D4, + 0x2202, 0x2208, 0x220F, 0x221D, + 0x2245, 0x2284, 0x2286, 0x2287, + 0x22A5, 0x22C5, 0x2329, 0x232A + }; + for( size_t i = 0; i < entries; ++i ) + { + if ( *reinterpret_cast( c ) == + *reinterpret_cast( e4[i] ) ) + { + return c4[i]; + } + } + } + else if ( 5 == len ) + { + const int entries = 72; + static const char e5[entries][5] = { + {'i','e','x','c','l'}, {'p','o','u','n','d'}, {'l','a','q','u','o'}, {'a','c','u','t','e'}, + {'m','i','c','r','o'}, {'c','e','d','i','l'}, {'r','a','q','u','o'}, {'A','c','i','r','c'}, + {'A','r','i','n','g'}, {'A','E','l','i','g'}, {'E','c','i','r','c'}, {'I','c','i','r','c'}, + {'O','c','i','r','c'}, {'t','i','m','e','s'}, {'U','c','i','r','c'}, {'T','H','O','R','N'}, + {'s','z','l','i','g'}, {'a','c','i','r','c'}, {'a','r','i','n','g'}, {'a','e','l','i','g'}, + {'e','c','i','r','c'}, {'i','c','i','r','c'}, {'o','c','i','r','c'}, {'u','c','i','r','c'}, + {'t','h','o','r','n'}, {'O','E','l','i','g'}, {'o','e','l','i','g'}, {'t','i','l','d','e'}, + {'A','l','p','h','a'}, {'G','a','m','m','a'}, {'D','e','l','t','a'}, {'T','h','e','t','a'}, + {'K','a','p','p','a'}, {'S','i','g','m','a'}, {'O','m','e','g','a'}, {'a','l','p','h','a'}, + {'g','a','m','m','a'}, {'d','e','l','t','a'}, {'t','h','e','t','a'}, {'k','a','p','p','a'}, + {'s','i','g','m','a'}, {'o','m','e','g','a'}, {'u','p','s','i','h'}, {'n','d','a','s','h'}, + {'m','d','a','s','h'}, {'l','s','q','u','o'}, {'r','s','q','u','o'}, {'s','b','q','u','o'}, + {'l','d','q','u','o'}, {'r','d','q','u','o'}, {'b','d','q','u','o'}, {'p','r','i','m','e'}, + {'P','r','i','m','e'}, {'o','l','i','n','e'}, {'f','r','a','s','l'}, {'i','m','a','g','e'}, + {'t','r','a','d','e'}, {'c','r','a','r','r'}, {'e','x','i','s','t'}, {'e','m','p','t','y'}, + {'n','a','b','l','a'}, {'n','o','t','i','n'}, {'m','i','n','u','s'}, {'r','a','d','i','c'}, + {'i','n','f','i','n'}, {'a','s','y','m','p'}, {'e','q','u','i','v'}, {'o','p','l','u','s'}, + {'l','c','e','i','l'}, {'r','c','e','i','l'}, {'c','l','u','b','s'}, {'d','i','a','m','s'} + }; + static const wchar_t c5[entries] = { + 0x00A1, 0x00A3, 0x00AB, 0x00B4, + 0x00B5, 0x00B8, 0x00BB, 0x00C2, + 0x00C5, 0x00C6, 0x00CA, 0x00CE, + 0x00D4, 0x00D7, 0x00DB, 0x00DE, + 0x00DF, 0x00E2, 0x00E5, 0x00E6, + 0x00EA, 0x00EE, 0x00F4, 0x00FB, + 0x00FE, 0x0152, 0x0153, 0x02DC, + 0x0391, 0x0393, 0x0394, 0x0398, + 0x039A, 0x03A3, 0x03A9, 0x03B1, + 0x03B3, 0x03B4, 0x03B8, 0x03BA, + 0x03C3, 0x03C9, 0x03D2, 0x2013, + 0x2014, 0x2018, 0x2019, 0x201A, + 0x201C, 0x201D, 0x201E, 0x2032, + 0x2033, 0x203E, 0x2044, 0x2111, + 0x2122, 0x21B5, 0x2203, 0x2205, + 0x2207, 0x2209, 0x2212, 0x221A, + 0x221E, 0x2248, 0x2261, 0x2295, + 0x2308, 0x2309, 0x2663, 0x2666 + }; + for( size_t i = 0; i < entries; ++i ) + { + if ( 0 == strncmp( const_cast( c ), e5[i], 5 ) ) + { + return c5[i]; + } + } + } + else if ( 6 == len ) + { + const int entries = 62; + static const char e6[entries][6] = { + {'c','u','r','r','e','n'}, {'b','r','v','b','a','r'}, {'p','l','u','s','m','n'}, {'m','i','d','d','o','t'}, + {'f','r','a','c','1','4'}, {'f','r','a','c','1','2'}, {'f','r','a','c','3','4'}, {'i','q','u','e','s','t'}, + {'A','g','r','a','v','e'}, {'A','a','c','u','t','e'}, {'A','t','i','l','d','e'}, {'C','c','e','d','i','l'}, + {'E','g','r','a','v','e'}, {'E','a','c','u','t','e'}, {'I','g','r','a','v','e'}, {'I','a','c','u','t','e'}, + {'N','t','i','l','d','e'}, {'O','g','r','a','v','e'}, {'O','a','c','u','t','e'}, {'O','t','i','l','d','e'}, + {'O','s','l','a','s','h'}, {'U','g','r','a','v','e'}, {'U','a','c','u','t','e'}, {'Y','a','c','u','t','e'}, + {'a','g','r','a','v','e'}, {'a','a','c','u','t','e'}, {'a','t','i','l','d','e'}, {'c','c','e','d','i','l'}, + {'e','g','r','a','v','e'}, {'e','a','c','u','t','e'}, {'i','g','r','a','v','e'}, {'i','a','c','u','t','e'}, + {'n','t','i','l','d','e'}, {'o','g','r','a','v','e'}, {'o','a','c','u','t','e'}, {'o','t','i','l','d','e'}, + {'d','i','v','i','d','e'}, {'o','s','l','a','s','h'}, {'u','g','r','a','v','e'}, {'u','a','c','u','t','e'}, + {'y','a','c','u','t','e'}, {'S','c','a','r','o','n'}, {'s','c','a','r','o','n'}, {'L','a','m','b','d','a'}, + {'l','a','m','b','d','a'}, {'s','i','g','m','a','f'}, {'t','h','i','n','s','p'}, {'d','a','g','g','e','r'}, + {'D','a','g','g','e','r'}, {'h','e','l','l','i','p'}, {'p','e','r','m','i','l'}, {'l','s','a','q','u','o'}, + {'r','s','a','q','u','o'}, {'w','e','i','e','r','p'}, {'f','o','r','a','l','l'}, {'l','o','w','a','s','t'}, + {'t','h','e','r','e','4'}, {'o','t','i','m','e','s'}, {'l','f','l','o','o','r'}, {'r','f','l','o','o','r'}, + {'s','p','a','d','e','s'}, {'h','e','a','r','t','s'} + }; + static const wchar_t c6[entries] = { + 0x00A4, 0x00A6, 0x00B1, 0x00B7, + 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C3, 0x00C7, + 0x00C8, 0x00C9, 0x00CC, 0x00CD, + 0x00D1, 0x00D2, 0x00D3, 0x00D5, + 0x00D8, 0x00D9, 0x00DA, 0x00DD, + 0x00E0, 0x00E1, 0x00E3, 0x00E7, + 0x00E8, 0x00E9, 0x00EC, 0x00ED, + 0x00F1, 0x00F2, 0x00F3, 0x00F5, + 0x00F7, 0x00F8, 0x00F9, 0x00FA, + 0x00FD, 0x0160, 0x0161, 0x039B, + 0x03BB, 0x03C2, 0x2009, 0x2020, + 0x2021, 0x2026, 0x2030, 0x2039, + 0x203A, 0x2118, 0x2200, 0x2217, + 0x2234, 0x2297, 0x230A, 0x230B, + 0x2660, 0x2665 + }; + for( size_t i = 0; i < entries; ++i ) + { + if ( 0 == strncmp( const_cast( c ), e6[i], 6 ) ) + { + return c6[i]; + } + } + } + else if ( 7 == len ) + { + const int entries = 7; + static const char e7[entries][7] = { + {'E','p','s','i','l','o','n'}, {'O','m','i','c','r','o','n'}, + {'U','p','s','i','l','o','n'}, {'e','p','s','i','l','o','n'}, + {'o','m','i','c','r','o','n'}, {'u','p','s','i','l','o','n'}, + {'a','l','e','f','s','y','m'} + }; + static const wchar_t c7[entries] = { + 0x0395, 0x039F, 0x03A5, 0x03B5, + 0x03BF, 0x03C5, 0x2135 + }; + for( size_t i = 0; i < entries; ++i ) + { + if ( 0 == strncmp( const_cast( c ), e7[i], 7 ) ) + { + return c7[i]; + } + } + } + else if ( 8 == len ) + { + if ( 0 == strncmp( const_cast( c ), "thetasym", 8 ) ) + { + return 0x03D1; + } + } + return 0; + } +} diff --git a/nsdfont/src/UnicodeString.h b/nsdfont/src/UnicodeString.h new file mode 100755 index 0000000..d5d6e34 --- /dev/null +++ b/nsdfont/src/UnicodeString.h @@ -0,0 +1,47 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + +#pragma once + +#define NOMINMAX +#include + +namespace nsdfont +{ + class UnicodeString + { + public: + enum Codepage + { + SJIS = 932, + UTF8 = CP_UTF8, + }; + private: + wchar_t *unicodeStr; + size_t length; + size_t position; + + public: + UnicodeString( Codepage codepage, const char *str, size_t length = -1 ); + ~UnicodeString( void ); + + unsigned int peek( void ); + inline void rewind( void ){ position = 0; } + private: + /** + * Œ»Ý‚̈ʒu‚©‚琔’l•¶ŽšŽQÆ‚ð‰ðÍ‚µ•¶ŽšƒR[ƒh‚ð•Ô‚·. + * @retrun ŽQÆ‚³‚ê‚Ä‚¢‚镶ŽšƒR[ƒh. Ž¸”s‚µ‚½ê‡‚̓[ƒ + */ + unsigned int parseNumericEntity( void ); + /** + * Œ»Ý‚̈ʒu‚©‚çŽÀ‘Ì•¶ŽšŽQÆ‚ð‰ðÍ‚µ•¶ŽšƒR[ƒh‚ð•Ô‚·. + * @retrun ŽQÆ‚³‚ê‚Ä‚¢‚镶ŽšƒR[ƒh. Ž¸”s‚µ‚½ê‡‚̓[ƒ + */ + unsigned int parseCharacterEntity( void ); + }; +} + diff --git a/nsdfont/src/main.cpp b/nsdfont/src/main.cpp new file mode 100755 index 0000000..419e7a8 --- /dev/null +++ b/nsdfont/src/main.cpp @@ -0,0 +1,176 @@ +/* + * Kimikage NScripter Plugins Project + * + * This software is distributed under a BSD-style license. + * See license.txt for more information. + */ + + +#define NOMINMAX +#include +#include +#include + +#include "nslua.h" +#include "Glyph.h" +#include "UnicodeString.h" +#include "ArgbBitmap.h" +#include "Decorator.h" +#include "Typesetter.h" +using namespace nsdfont; + +extern "C" { + __declspec(dllexport) void Font( unsigned char *bits, int w, int h, const char *param ); + __declspec(dllexport) LUALIB_API int luaopen_nsdfont( lua_State *L ); +} + +static NL_gettablePtr NL_gettable = NULL; +static NL_isstringPtr NL_isstring = NULL; +static NL_istablePtr NL_istable = NULL; +static NL_popPtr NL_pop = NULL; +static NL_pushintegerPtr NL_pushinteger = NULL; +static NL_pushstringPtr NL_pushstring = NULL; +static NL_tobooleanPtr NL_toboolean = NULL; +static NL_tointegerPtr NL_tointeger = NULL; +static NL_tonumberPtr NL_tonumber = NULL; +static NL_tostringPtr NL_tostring = NULL; + +static Decorator decorator; +static Typesetter setter; + + +BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) +{ + return TRUE; +} + +static int setFont( lua_State *L ) +{ + LOGFONT lf; + memset( &lf, 0, sizeof(lf) ); + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfEscapement = 0; + lf.lfItalic = 0; + lf.lfOrientation = 0; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfPitchAndFamily = DEFAULT_PITCH; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfStrikeOut = 0; + lf.lfUnderline = 0; + lf.lfWidth = 0; + double expansion = 1.0; + double angleX = 0.0; + double angleY = 0.0; + const char *face = NULL; + if ( NL_istable( L, 1 ) ) + { + NL_pushstring( L, "face" ); // 1:table, 2:"face" + NL_gettable( L, 1 ); // 1:table, 2:face + face = NL_tostring( L, 2 ); + NL_pushstring( L, "size" ); + NL_gettable( L, 1 ); + lf.lfHeight = NL_tointeger( L, 3 ); // 1:table, 2:face, 3:size + NL_pushstring( L, "weight" ); + NL_gettable( L, 1 ); + lf.lfWeight = NL_tointeger( L, 4 ); + NL_pushstring( L, "italic" ); + NL_gettable( L, 1 ); + lf.lfItalic = static_cast( NL_toboolean( L, 5 ) ); + NL_pushstring( L, "expansion" ); + NL_gettable( L, 1 ); + expansion = NL_tonumber( L, 6 ); + NL_pushstring( L, "angleX" ); + NL_gettable( L, 1 ); + angleX = NL_tonumber( L, 7 ); + NL_pushstring( L, "angleY" ); + NL_gettable( L, 1 ); + angleY = NL_tonumber( L, 8 ); + NL_pop( L, 7 ); // 1:table + } + else if ( NL_isstring( L, 1 ) ) + { + face = NL_tostring( L, 1 ); // face + lf.lfHeight = NL_tointeger( L, 2 ); // size + lf.lfWeight = NL_tointeger( L, 3 ); // weight + lf.lfItalic = static_cast( NL_toboolean( L, 4 ) ); // italic + expansion = NL_tonumber( L, 5 ); // expansion + angleX = NL_tonumber( L, 6 ); // angleX + angleY = NL_tonumber( L, 7 ); // angleY + } + else + { + return 0; + } + if ( face ) strcpy_s( lf.lfFaceName, sizeof( lf.lfFaceName ), face ); + if ( lf.lfFaceName[0] == 0 ) + { + strcpy_s( lf.lfFaceName, sizeof( lf.lfFaceName ), "‚l‚r ‚oƒSƒVƒbƒN" ); + } + if ( lf.lfHeight == 0 ) lf.lfHeight = 24; + if ( lf.lfWeight == 0 ) lf.lfWeight = FW_NORMAL; + if ( expansion < 1e-20 ) expansion = 1.0; + + Glyph::setFont( &lf ); + Glyph::setTransformation( expansion, angleX, angleY ); + return 0; +} + +static int setFace( lua_State *L ) +{ + const unsigned int color1 = static_cast( NL_tointeger( L, 1 ) );; + decorator.setFace( Color( color1, 0xFF ) ); + return 0; +} + +static int setEdge( lua_State *L ) +{ + const double width = NL_tonumber( L, 1 ); + const unsigned int color1 = static_cast( NL_tonumber( L, 2 ) ); + decorator.setEdge( width, Color( color1 ) ); + return 0; +} + +static int calculateRect( lua_State *L ) +{ + int width, height; + const char *str = NL_tostring( L, 1 ); + UnicodeString unicodeStr( UnicodeString::SJIS, str ); + setter.calculateRect( width, height, unicodeStr, decorator ); + NL_pushinteger( L, width ); + NL_pushinteger( L, height ); + return 2; +} + +LUALIB_API int luaopen_nsdfont( lua_State *L ) +{ + HMODULE hMod = GetModuleHandleA( "nslua.dll" ); + NL_registerPtr NL_register = NULL; + NL_register = reinterpret_cast( GetProcAddress( hMod, "NL_register" ) ); + NL_gettable = reinterpret_cast( GetProcAddress( hMod, "NL_gettable" ) ); + NL_isstring = reinterpret_cast( GetProcAddress( hMod, "NL_isstring" ) ); + NL_istable = reinterpret_cast( GetProcAddress( hMod, "NL_istable" ) ); + NL_pop = reinterpret_cast( GetProcAddress( hMod, "NL_pop" ) ); + NL_pushinteger = reinterpret_cast( GetProcAddress( hMod, "NL_pushinteger" ) ); + NL_pushstring = reinterpret_cast( GetProcAddress( hMod, "NL_pushstring" ) ); + NL_toboolean = reinterpret_cast( GetProcAddress( hMod, "NL_toboolean" ) ); + NL_tostring = reinterpret_cast( GetProcAddress( hMod, "NL_tostring" ) ); + NL_tointeger = reinterpret_cast( GetProcAddress( hMod, "NL_tointeger" ) ); + NL_tonumber = reinterpret_cast( GetProcAddress( hMod, "NL_tonumber" ) ); + NL_register( "nsdfont_calcRect", &calculateRect ); + NL_register( "nsdfont_setFont", &setFont ); + NL_register( "nsdfont_setFace", &setFace ); + NL_register( "nsdfont_setEdge", &setEdge ); + return 0; +} + +void Font(unsigned char *bits, int width, int height, const char *param ) +{ + ArgbBitmap bmp( width, height, bits ); + UnicodeString str( UnicodeString::SJIS, param ); + //decorator.setEdge(0.1,Color(0xFF0000,255) ); + setter.draw( bmp, str, decorator ); + return; +} + + diff --git a/nsdfont/vs2005/nsdfont.sln b/nsdfont/vs2005/nsdfont.sln new file mode 100755 index 0000000..4396021 --- /dev/null +++ b/nsdfont/vs2005/nsdfont.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsdfont", "nsdfont.vcproj", "{41D757BC-8A62-43E0-8F1D-7FBC28059DA9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {41D757BC-8A62-43E0-8F1D-7FBC28059DA9}.Debug|Win32.ActiveCfg = Debug|Win32 + {41D757BC-8A62-43E0-8F1D-7FBC28059DA9}.Debug|Win32.Build.0 = Debug|Win32 + {41D757BC-8A62-43E0-8F1D-7FBC28059DA9}.Release|Win32.ActiveCfg = Release|Win32 + {41D757BC-8A62-43E0-8F1D-7FBC28059DA9}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/nsdfont/vs2005/nsdfont.vcproj b/nsdfont/vs2005/nsdfont.vcproj new file mode 100755 index 0000000..62e1907 --- /dev/null +++ b/nsdfont/vs2005/nsdfont.vcproj @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.11.0