Re: 文字の一部分だけに色を付ける方法について ( No.1 ) |
- 名前:MOR 日時:2019/03/24 22:06
volatile.hatenablog.com/entry/2019/03/16/135308 のコードを使ってみましたが、確かに重いですね。
昨年 dxlib.xsrv.jp/cgi/patiobbs/patio.cgi?mode=view&no=4510 に書いたものを一部変更してみました。
ただし「Unicode専用版」なので注意して下さい。(マルチバイトだと表示されない)
元のサンプルでは25〜30fpsくらいでしたが、これだとだいたい60fpsくらいでているかと思います。
ただし、色の指定方法が大変なので、使いやすさでは遥かに劣りますが...
#include "DxLib.h"
#include <vector>
#include <string>
using namespace std;
typedef std::basic_string<TCHAR> tstring;
#define ALIGNMENT_LEFT 0
#define ALIGNMENT_CENTER 1
#define ALIGNMENT_RIGHT 2
// 文字ごとの色変更版DrawString (手抜きなのでUnicode専用版にしてあります)
//
// bApplyCRColor = TRUEなら、改行文字('\n')にもダミー色を割り当ててあるとして処理
// 位置寄せ指定は『改行後の文字』が対象なので、一行目は左寄せ固定。
// nLineInterval = 改行の際のドット数 (DrawStringの改行ドット数はWindowsとAndroidで挙動が違うが法則がわからなかったので手動にした)
int DrawStringToHandleWithColorArray(int x, int y, const TCHAR* pStr, int FontHandle, unsigned int* pColorCodeArray, int bApplyCRColor, int nLineInterval, int nPosAlignment = ALIGNMENT_LEFT)
{
if (pStr == NULL) return -1;
if (pColorCodeArray == NULL) return -1;
const TCHAR *lpStr = pStr;
vector<vector<TCHAR>> vct;
vector<TCHAR> vct0;
int SizeX, SizeY = 0, ColorBitDepth = 0;
RECT rc;
DxLib::GetDrawArea(&rc);
SizeX = rc.right;
int nFSize = DxLib::GetFontSize(), xs = x;
size_t uiSize = DxLib::strlen2Dx(pStr);
unsigned int uiCL = 0, ui2 = 0;
int tt = 0;
int CharBytes = 0;
TCHAR c;
TCHAR cc[10];
for (unsigned int ui = 0; ui < uiSize; ui++)
{
CharBytes = DxLib::GetCharBytes(DX_CHARCODEFORMAT_UTF16LE, lpStr + ui2) / 2;
if (CharBytes == 1)
{
c = *(lpStr + ui2++);
if (c == '\n')
{
vct.push_back(vct0);
vct0.clear();
}
else {
vct0.push_back(c);
}
}
else {
for (int i = 0; i < CharBytes; i++)
{
c = *(lpStr + ui2++);
vct0.push_back(c);
}
}
}
if (vct0.size() > 0)
{
vct.push_back(vct0);
vct0.clear();
}
for (unsigned int i = 0; i < vct.size(); i++)
{
vct0 = vct[i];
int xss = 0;
if (nPosAlignment == ALIGNMENT_CENTER && i > 0)
{
for (unsigned int k = 0; k < vct0.size(); k++)
{
cc[0] = vct0[k];
CharBytes = DxLib::GetCharBytes(DX_CHARCODEFORMAT_UTF16LE, &cc[0]) / 2;
for (int m = 1; m < CharBytes; m++)
{
cc[m] = vct0[++k];
}
cc[CharBytes] = '\0';
xss += DxLib::GetDrawStringWidthToHandle(cc, CharBytes, FontHandle);
}
x = (SizeX - xss) / 2;
}
else if (nPosAlignment == ALIGNMENT_RIGHT && i > 0)
{
for (unsigned int k = 0; k < vct0.size(); k++)
{
cc[0] = vct0[k];
CharBytes = DxLib::GetCharBytes(DX_CHARCODEFORMAT_UTF16LE, &cc[0]) / 2;
for (int m = 1; m < CharBytes; m++)
{
cc[m] = vct0[++k];
}
cc[CharBytes] = '\0';
xss += DxLib::GetDrawStringWidthToHandle(cc, CharBytes, FontHandle);
}
x = SizeX - xss;
}
else
{
x = xs;
}
for (unsigned int j = 0; j < vct0.size(); j++)
{
cc[0] = vct0[j];
CharBytes = DxLib::GetCharBytes(DX_CHARCODEFORMAT_UTF16LE, &cc[0]) / 2;
for (int m = 1; m < CharBytes; m++)
{
cc[m] = vct0[++j];
}
cc[CharBytes] = '\0';
DxLib::DrawStringToHandle(x, y, cc, pColorCodeArray[uiCL++], FontHandle);
x += DxLib::GetDrawStringWidthToHandle(cc, CharBytes, FontHandle);
}
if (bApplyCRColor) uiCL++;
y += nLineInterval;
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
DxLib::ChangeWindowMode(TRUE);
DxLib::SetGraphMode(1280, 720, 32);
DxLib::SetAlwaysRunFlag(TRUE);
if (DxLib::DxLib_Init() < 0) return -1;
DxLib::SetDrawMode(DX_DRAWMODE_BILINEAR);
DxLib::SetDrawScreen(DX_SCREEN_BACK);
DxLib::SetBackgroundColor(192, 192, 192);
DxLib::SetFontCacheCharNum(2048);
int FontHandle = DxLib::CreateFontToHandle(NULL, 16, 3, DX_FONTTYPE_ANTIALIASING_EDGE_8X8);
unsigned uiCounter = 0, uiCounter2 = 0;
while (DxLib::ProcessMessage() == 0)
{
DxLib::ClearDrawScreen();
TCHAR string[1000];
// 文字列は volatile.hatenablog.com/entry/2019/03/16/135308 から拝借
DxLib::sprintfDx(string, TEXT("あのイーハトーヴォのすきとおった風、"
"夏でも底に冷たさをもつ青いそら、\n"
"うつくしい森で飾られたモリーオ市、"
"郊外のぎらぎらひかる草の波。\n"
"Lorem ipsum dolor sit amet, consectetur adipiscing elit,\n"
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n"
"%d + %d = %d"), 30, 40, 30 + 40);
size_t uiSize = DxLib::strlen2Dx(string);
unsigned int *puiCArray = new unsigned int[uiSize];
for (unsigned int ui = 0; ui < uiSize; ui++)
{
puiCArray[ui] = DxLib::GetColor((uiCounter2 + ui & 2) ? 255 : 0, (uiCounter2 + ui & 4) ? 255 : 0, (uiCounter2 + ui & 1) ? 255 : 0);
}
if (uiCounter++ % 30 == 0) uiCounter2++;
int nn = 20; // 改行のドット数
DrawStringToHandleWithColorArray(0, 100, string, FontHandle, puiCArray, TRUE, nn); // 改行でも色カウンターを進める・左寄せ
DrawStringToHandleWithColorArray(0, 250, string, FontHandle, puiCArray, TRUE, nn);
DrawStringToHandleWithColorArray(0, 400, string, FontHandle, puiCArray, TRUE, nn);
delete[] puiCArray;
DxLib::DrawFormatString(0, 0, GetColor(255, 255, 255), TEXT("%dFPS"), (int)DxLib::GetFPS());
if (DxLib::ScreenFlip() != 0) break;
}
DxLib::InitFontToHandle();
return DxLib::DxLib_End();
}
|
Re: 文字の一部分だけに色を付ける方法について ( No.2 ) |
- 名前:yumetodo 日時:2019/03/24 23:25
> nLineInterval
GetFontLineSpaceToHandleで取ってこれるものとはまた違うんでしょうか
ref: ttps: //qiita.com/yumetodo/items/8180d48b6fca18d78a90
|
Re: 文字の一部分だけに色を付ける方法について ( No.3 ) |
- 名前:MOR 日時:2019/03/25 19:58
> GetFontLineSpaceToHandleで取ってこれるものとはまた違うんでしょうか
例えば
int FontHandle = DxLib::CreateFontToHandle(NULL, 16, 3, DX_FONTTYPE_ANTIALIASING_EDGE_8X8);
int n = DxLib::GetFontLineSpaceToHandle(FontHandle);
とやってみると、戻り値 n は
Windows 10 ... 20
Android実機 ... 28
iOSシミュレーター ... 26
のようにバラバラなので、現状ではY方向の位置を強制指定しないと見た目がそろいません。
(…と書きかけて DxLib::SetFontLineSpaceToHandle(20); とやっておけばいいと気が付きました)
|
Re: 文字の一部分だけに色を付ける方法について ( No.4 ) |
- 名前:管理人 日時:2019/03/26 00:45
Debug版の std が非常に重いのが fps が半分以下になる原因みたいです
なので、Releaseビルドでは fpsが半分以下になることはないと思いますが
開発中も常に Releaseビルドだとデバッグ作業に支障をきたしそうですね…
MORさんが既に解決のアイディアをご提案されていますが、私もNさんがご紹介
されたサイト( ttp://volatile.hatenablog.com/entry/2019/03/16/135308 )と
同じ書式で色が付けられる std を使用しないプログラムを組んでみましたので
よろしければご覧ください m(_ _)m
( 因みに私のサンプルは MORさんのプログラムとは逆にマルチバイト専用です… )
#include <DxLib.h>
#include <string.h>
// 16進数の2桁の数字を数値に変換する
int GetNum16( const char *NumStr )
{
int Num = 0 ;
if( NumStr[ 0 ] >= 'a' && NumStr[ 0 ] <= 'f' )
{
Num += ( NumStr[ 0 ] - 'a' + 10 ) * 16 ;
}
else
{
Num += ( NumStr[ 0 ] - '0' ) * 16 ;
}
if( NumStr[ 1 ] >= 'a' && NumStr[ 1 ] <= 'f' )
{
Num += NumStr[ 1 ] - 'a' + 10 ;
}
else
{
Num += NumStr[ 1 ] - '0' ;
}
return Num ;
}
void DrawFormatStringToHandleColor(const int x, const int y, const unsigned int Color, const int FontHandle, const char *FormatString, ... )
{
va_list VaList ;
char String[ 4096 ];
char TempString[ 4096 ] ;
const char *StringP ;
int DrawX, DrawY ;
int LineHeight ;
int TempStringBytes ;
int CharCodeFormat ;
int NowColor ;
int CharBytes ;
// 書式文字列から文字列を作成する
va_start( VaList, FormatString ) ;
vsnprintfDx( String, sizeof( String ) - 1, FormatString, VaList ) ;
va_end( VaList ) ;
// 使用している文字コード形式を取得
CharCodeFormat = GetUseCharCodeFormat() ;
// フォントの高さを取得しておく
LineHeight = GetFontLineSpaceToHandle( FontHandle ) ;
// 描画位置の初期化
DrawX = x ;
DrawY = y ;
// 色をセット
NowColor = Color ;
// 描画する文字列の長さを初期化
TempStringBytes = 0 ;
// 文字列のアドレスをセット
StringP = String ;
// 文字列の終端に到達するまでループ
while( *StringP != '\0' )
{
// 1文字のバイト数を取得
CharBytes = GetCharBytes( CharCodeFormat, StringP ) ;
// 1文字が1バイト以上の場合は全角文字として判断
if( CharBytes > 1 )
{
// 描画する文字列に1文字分コピー
memcpy( &TempString[ TempStringBytes ], StringP, CharBytes ) ;
TempStringBytes += CharBytes ;
TempString[ TempStringBytes ] = '\0' ;
// 文字列のアドレスを1文字分進める
StringP += CharBytes ;
}
else
// [ だったら色変更関係として処理
if( StringP[ 0 ] == '[' )
{
// 描画する文字列があったらここで描画する
if( TempStringBytes > 0 )
{
DrawStringToHandle( DrawX, DrawY, TempString, NowColor, FontHandle ) ;
// 描画 x 座標を描画文字列の幅分だけ右側に移動する
DrawX += GetDrawStringWidthToHandle( TempString, -1, FontHandle ) ;
// 描画文字列の長さを初期化
TempStringBytes = 0 ;
}
// 2文字目が - の場合は色を元に戻す
if( StringP[ 1 ] == '-' )
{
NowColor = Color ;
// [-] の 3文字分アドレスを進める
StringP += 3 ;
}
else
{
// それ以外の場合は文字の色を読み取る
NowColor = GetColor( GetNum16( &StringP[ 1 ] ), GetNum16( &StringP[ 3 ] ), GetNum16( &StringP[ 5 ] ) ) ;
// [RRGGBB] の 8文字分アドレスを進める
StringP += 8 ;
}
}
else
// 改行文字の場合は描画文字位置を改行する
if( StringP[ 0 ] == '\n' )
{
// 描画する文字列があったらここで描画する
if( TempStringBytes > 0 )
{
DrawStringToHandle( DrawX, DrawY, TempString, NowColor, FontHandle ) ;
// 描画文字列の長さを初期化
TempStringBytes = 0 ;
}
// 描画 x 座標を最初の位置に戻す
DrawX = x ;
// 描画 y 座標を1行分下にずらす
DrawY += LineHeight ;
// 改行文字の 1文字分アドレスを進める
StringP++ ;
}
else
// 上記以外の場合は 1バイトの 1文字
{
// 描画文字列に 1文字加える
TempString[ TempStringBytes ] = *StringP ;
TempStringBytes++ ;
TempString[ TempStringBytes ] = '\0' ;
// アドレスを 1文字分進める
StringP++ ;
}
}
// 描画する文字列があったらここで描画する
if( TempStringBytes > 0 )
{
DrawStringToHandle( DrawX, DrawY, TempString, NowColor, FontHandle ) ;
}
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
// ウインドウモードで起動
ChangeWindowMode( TRUE ) ;
// 画面モードをセット
SetGraphMode( 1024, 480, 32 ) ;
// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1 ;
// 描画先を裏画面にする
SetDrawScreen( DX_SCREEN_BACK ) ;
const char *string = "あの[fc585a]イーハトーヴォ[-]の[49b21f]すきとおった風[-]、"
"[eb8900]夏[-]でも[2ed2fd]底に冷たさをもつ青いそら[-]、\n"
"[49b21f]うつくしい森[-]で飾られた[fc585a]モリーオ市[-]、"
"[fc585a]郊外[-]の[fdbf2d]ぎらぎらひかる[49b21f]草の波[-]。\n"
"[ff0000]Lorem ipsum dolor sit amet, [00ff00]consectetur adipiscing elit,\n"
"[0000ff]sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.[-]\n"
"%d + %d = [abcdef]%d";
// フォントハンドルの作成
int FontHandle = CreateFontToHandle( NULL, 20, 4, DX_FONTTYPE_NORMAL ) ;
// 背景の色を灰色にする
SetBackgroundColor( 128,128,128 ) ;
// メインループ
while( ProcessMessage() == 0 )
{
// 画面のクリア
ClearDrawScreen() ;
DrawFormatStringToHandleColor(0, 100, 0xffffff, FontHandle, string, 30, 40, 30 + 40);
// 裏画面の内容を表画面に反映
ScreenFlip() ;
}
// DXライブラリの後始末
DxLib_End() ;
// ソフトの終了
return 0 ;
}
あと、このサンプルでは今回新たに追加した関数 GetUseCharCodeFormat を
使用していますので、お手数で申し訳ありませんが関数を追加したこちらの
バージョンを使用してください m(_ _;m
https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用
https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用
https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 10.2 用
https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用
https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用
https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM.zip // Android版 ARM用
https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM64.zip // Android版 ARM64用
https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x86.zip // Android版 x86用
https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x64.zip // Android版 x64用
https://dxlib.xsrv.jp/temp/DxLibiOSTest.zip // iOS版
https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース
(中身を既存のライブラリのファイルに上書きして『リビルド』をして下さい)
|
Re: 文字の一部分だけに色を付ける方法について ( No.5 ) |
- 名前:Nさん 日時:2019/03/26 12:55
MORさん、管理人さんありがとうございます。試してみたいと思います
|
|