HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2009
0831
ナナシmesの限界?6解決


ナナシ

リンク

2009/8/31(Mon) 00:57:54|NO.27463

初めまして。早速ですが質問をさせて頂きます。
私は他のプログラミング言語を使っていたのですが、それの速度がかなり遅いので、急遽HSPを勉強しています。
現在、文字を並べたものを連続再生することにより動画にするいわゆる「AA動画」のプレイヤーを作っています。
1枚1枚のデータはtxtファイルとして作成し終えていますが、それをmesで表示すると何文字目か(512だと思いますが)で自動で改行してしまうようです。
ループ部分のみ抜粋します
notesel p1
repeat 2849 b=cnt+5 buffer b,1400,850,1 await 0 loop repeat 2849 noteload str(cnt)+".txt" b=cnt+5 gsel b palcolor 0 font "MS ゴシック",2,0 mes p1 gsel 0 await 0 loop
起動時に予めbufferへ書き込んでおき、後のループでメインウィンドウへgcopyしていく形となります。
txtのサイズは全角640x480です。3000枚ほどあります。320x240でやったときはこれで上手いこと再生されたのですが、
640x480だと前述したように1行1行が特定の文字数目で改行されてしまい、うまく表示されません。
色々試してみたところmesがそういう仕様のようですが、これを避ける方法はないですか?
repeat 2849
notesel p1 noteload str(cnt)+".txt" p5="" p6="" repeat 479 noteget p2,cnt p3=strmid(p2,0,640) p4=strmid(p2,640,1280) p5+="\n"+p3 p6+="\n"+p4          await 0 loop notesel p5 notedel 0 notesel p6 notedel 0 gsel cnt+5 pos 0,0 font "MS ゴシック",2 mes p5 posx=ginfo(14) pos posx,0 mes p6 await 0 loop
左右二つに分けて表示するこの方法だと一応うまくいくのですが、やはり中のループ部分の処理が遅く、
読込に1日かかりそうな鈍さです。
やはり一気に表示しないと厳しそうですが何か良い方法はありませんか?ご教授よろしくお願いします。



この記事に返信する


つーか

リンク

2009/8/31(Mon) 03:22:05|NO.27464

> repeat 479
> noteget p2,cnt
> p3=strmid(p2,0,640)
> p4=strmid(p2,640,1280)
> p5+="\n"+p3
> p6+="\n"+p4
>         await 0
> loop
ちょっとwww
strmidはかなり遅い命令なので毎フレーム960回呼ぶと死にます。

div = 4
size = 640*(480/div)
p3=strmid(p2,size*0,size*1)
p4=strmid(p2,size*1,size*2)
p5=strmid(p2,size*2,size*3)
p6=strmid(p2,size*3,size*4)
;   ↑がsize*divになるまでコピペ
; repeatでもok(cntの仕様忘れたので:p)

320*240ではokだったのだから、640*480は4倍の容量なので4分割してます。
これでも足りなければ分割数を増やせばokですtai!



ナナシ

リンク

2009/8/31(Mon) 07:39:53|NO.27466

回答ありがとうございます。
なるほど・・・strmidの重さで余計厳しいわけですね・・・
つーかさんの例を拝見させて頂きましたが、これでは縦に分割になってしまうと思います。
「mesの文章数に限界がある」のではなく「mesの一行の文字数に限界がある」ということです。
なので恐らくそのソースでも同じ結果になってしまうと思います・・・うまく伝わっていなくてすみません。
そういうことで横に分割するためあんなループしなければならなかったのですが、
なんとかならないものでしょうか。



窓口

リンク

2009/8/31(Mon) 08:57:22|NO.27467

よくわかりませんが、こんなのはいかがですか?
もし違っていたらごめんなさい。

strmidではなくmemcpyを使用してみました。
ウインドウのサイズと文字の描絵サイズからmesする文字数を割り出します。
ウインドウの右端でちょうど改行される仕組みになっております。
ウインドウサイズを変更しても動作は変わりません。


#define X 0 ; 配列変数 msg_size  screen_size の 引数に使用してください #define Y 1 ; 変更しないで下さい ;################################################################################ #define scX 640 ; スクリーンのサイズの定義です #define scY 480 ; 変更するとサイズが変わります ;改行判定をする場合ここの数値を変えて下さい ;#if ~ #endif によりコンパイルし分けます #define FLG 0 ; 0 改行判定をしない : 1 改行判定をする #define I 2000 ; これは処理する文字列を作成するためのループを制御する定義です。360 * I が作成される文字数となります。 ;################################################################################ screen 0 , scX , scY mes "あ" msg_size = ginfo(14) , ginfo(15) ;mes で描かれた文字サイズを取得 screen_size = ginfo(12) , ginfo(13) ;現在のスクリーンサイズを取得 ;------------------------------------- ;取得した設定を表示(システム本体とは関係ありません) mes strf("msg_size ( x[%d] : y[%d] )\nscreen_size ( x[%d] : y[%d])" , msg_size(x) , msg_size(y) , screen_size(x) , screen_size(y) ) mes "一行に表示できる文字数 : " + str(screen_size (x) / msg_size(x)) dialog "取得された設定" : cls ;編集する文字列を作成(システム本体とは関係ありません) p = "このように、640ピクセルラインに文字の末端が合わせてプリントされます。\n640と言う数字はGinfo関数で取得されたスクリーンのxサイズです。スクリーンのサイズを変えた場合でも、正常に動作します。速度を考えた為、文字を切り出す為にmemcpy命令を使用しています。仕様上、全角文字以外が入った場合文字化けが起こる可能性が有ります。改行にも対応しています。\n\n" strsize_ = I * strlen(p) dialog strlen(p) sdim mesg , strsize_ title "処理するテキストを作成しています。しばらくお待ちください。一分程度だと思います。" repeat I mesg += p loop mesbox mesg , ginfo (12) , ginfo (13) , 0 dialog strf("処理する文字列 %d 文字\n処理開始!" , strsize_ / 2 ) : cls ;表示の為の準備(システム本体とは関係ありません) screen 0 , screen_size (x)+100 , screen_size (y) line screen_size (x) , 0 , screen_size (x) , screen_size (y) pos screen_size (x),0 : mes "←"+ screen_size (x) + "\nライン" pos 0,0 ;------------------------------------- mid_strsize = (screen_size (x) / msg_size(x)) *2 sdim print_string , mid_strsize + 1 ;z = "" title "画面に書き込んでいます。しばらくお待ちください" ;メインループ redraw 0 repeat #if FLG = 1 #define MODE "改行判定モード" if (index >= strsize_) { cnt_ = cnt : break } memcpy print_string , mesg , mid_strsize , 0 , index if ( instr( print_string , 0 , "\n" ) ! -1 ) { g = instr( print_string , 0 , "\n" ) sdim print_string_2 , g+1 memcpy print_string_2 , print_string , g , 0 , 0 index += g + 2 mes print_string_2 }else{ mes print_string index += mid_strsize } #else #define MODE "非改行判定モード" if (mid_strsize * cnt >= strsize_) { cnt_ = cnt : break } memcpy print_string , mesg , mid_strsize , 0 , mid_strsize * cnt mes print_string #endif loop ;------------------------------------- redraw 1 title strf("%s で %d 回のmes を実行しました" , MODE , cnt_) dialog strf("%s で %d 回のmes を実行しました\n文字の末端までの処理が終了しました。" , MODE , cnt_)



ナナシ

リンク

2009/8/31(Mon) 13:04:57|NO.27471

回答ありがとうございます。
memcopyの方が高速なんですね。あとで試してみます。
ですがやはり大量のループとなってしまうので速度低下は免れなさそうです。

しかしすみません、説明不足が多くて・・・簡単に言えば超巨大なアスキーアートを表示したいのです。
まず640x480というのはスクリーンのサイズではなく、文字の数です。
txtファイルに横640文字×縦480文字の巨大アスキーアートが保存されていて、それを読み込んで表示させたいわけです。
簡単な例を作ってみました。

mozi="あいうえお" p1="" p2="" ;p1=「あいうえお×10(200文字)」 repeat 10 p1+=mozi loop ;p2=「あいうえお×104(520文字)」 repeat 104 p2+=mozi await 0 loop mes "サンプル1 ↓短い文字列だとこのように1行で表示されますが" mes p1+"\n" mes "サンプル2 ↓長い文字列となるとこのように勝手に改行してしまいます mes p2
実際は何行もあって、その通り表示されれば絵のように見えるのですが、
このように勝手に改行されてしまってうまくいかないのです。
私が2番目に書いたプログラムでは、これを「あいうえお×52」と「あいうえお×52」の二回に分けて表示することにより、
うまくいきましたが、なんせ480行もあるため1枚書くのに960回strmidしなければならず
膨大な時間がかかってしまいます。
ご理解頂けたでしょうか?

方向性としましては
・mesの限界を超えられる、他の命令を使用する(これができれば一番楽なのですが)
・つーかさんのような、一発で横に分けられる命令を使用する(昔使っていた言語では行の他に「列」という概念があったのですが)
・ループは仕方ないとしてもっとループ内を速くする(memcpy使ってみます)
・描画方法を根本的に変える
(bufferに予め描画しておきそれをメインウィンドウに次々とgcopyすることにより動画にしているのが現在)
といったところでしょうか。何かありましたら宜しくお願いします。



リンク

2009/8/31(Mon) 17:44:31|NO.27472

WindowsAPIのDrawTextを使えば、ウィンドウの端で勝手に改行
せずに文字列を描画できます。

って言っても、表示する範囲を強引に決めてるだけですけど……^^;
こんな感じの仕様で大丈夫でしょうか?


#uselib "user32.dll" #func DrawText "DrawTextA" int, sptr, int, sptr, int text = "" repeat 104 text += "あいうえお" await 0 loop ; DrawText で描画する範囲を作成 > 左上(0, 0) 右下(640, 480) の長方形範囲 ; ※ただし、この範囲からはみ出た文字は切り取られちゃうので注意 rect = 0, 0, 640, 480 ; 文字列描画 ↓この「text」が、描画する文字列 DrawText hdc, text, -1, varptr(rect), 0 ; redraw 1 で画面更新しないと表示されません redraw 1

描画する文字列が640*480のウィンドウサイズよりも
大きくなる場合(聞く限りではそのようですが……)
rectの3つ目の値をガンガン大きくしてみてください。



ナナシ

リンク

2009/8/31(Mon) 18:41:29|NO.27473

二番目のスクリプトを改良し、重い命令を置換えたところ
かなり速くなりました。

repeat maximg+1 noteload str(cnt)+".txt" p3="" p4="" repeat 479 memcpy p3,p1,640,cnt*641,cnt*1280 memcpy p4,p1,638,cnt*639,cnt*1280+640 poke p3,((cnt+1)*641)-1,'\n' poke p4,((cnt+1)*639)-1,'\n' loop poke p3,479*641-1,0 gsel cnt+5 pos 0,0 mes p3 posx=ginfo(14) pos posx,0 mes p4 await 0
ちなみにAA作成ミスで縦639x479になっていました;
note,strmidをmemcpyとpokeに置き換えただけです。ちょっと大変でしたが。

>光さん
ご回答ありがとうございます。
その方法で見事に成功しました!それが最速ではないかと思います。
ちなみにbufferなのでredrawしなくても大丈夫でした。


色々と勉強になりました。皆さんありがとうございます。それでは。



ONION software Copyright 1997-2021(c) All rights reserved.