2012年4月29日日曜日

日記ちゃん

 WMV9だとAVI2.0再生できないのか。
生成したファイルが正常なのかどうかがチェックできない問題が。
最初のRIFF-AVIは互換でみられるのだけど、RIFF-AVIX以降はどうしたものやら。


 実験的に2560x1920, 60fps10秒の動画を作成、
その後ffmpegで変換してみた。元のサイズが11.1GBだが、エンコードしたら6MBに。
ffmpegはデータがおかしくてもちゃんと変換してくれるから、あまり実験にはならないか。

2012年4月28日土曜日

日記ちゃん

Google Driveの使用テスト
test6.mp3
size: 489KB

test69_3.mp3
size: 1.78MB

目標ファイルのダウンロードに関してはSkyDriveよりわかりやすく
速度も速い。
共有設定も色々設定可能だけど、一部設定し忘れて予定外の公開方法をしちゃいそうだ。
SkyDriveだとPublicに放り込むだけだったから。
あとからフォルダ変えても公開アドレスは変わらないみたい。地味に便利。
フォルダにファイルを入れると、フォルダに設定された共有設定が反映される、
が一応チェックしないと不安ね。
 
 Bloggerで、行頭にスペースをおいても消されてしまうので と記述して無理やり空白を入れているが、
なんだか面倒くさい。
HTMLモードで記述するのだけど、こちらだと改行コードも自分でいれなければならない。

2012年4月21日土曜日

日記ちゃん

近辺で最大往生入荷なし!
赤い刀ですら新幹線で1時間ほど移動しないとないとかそれなくね。
むちぽがあるのがむしろレアだが。

Blogerの編集インターフェースが様変わりしてる。
それはいいんだけど、いままでのコードの改行コードが死滅してて編集しづらい。
追記
いつのまにやら改行が治っていたが、前はなかった<br />タグが追加されてる。
「作成」モードで<br />と打ち込んで「HTML」モードに切り替えても
&lt;br /&gt;と書き換えてくれないので
もう一度「作成」モードに切り替えた時に<br />って記述が消滅する。そのうち治るだろうとは思うが。
 
 しばらくFLStudioを使って遊んでたが、LMMSに戻ってきてしまった。
どうもFLStudioはバランス調整が難しい。

2012年4月18日水曜日

日記ちゃん最大往生あと二日


クリアな音で1面とボス曲が聞けて、自分には正解発表な気分でもある。
ACとプロモとでマスタリングが違うんじゃないかと思うぐらいバランスが違う気がする。
低音とか、笛っぽい音とかゲーセンだとこれで大丈夫なのかな……?
 ためしにモノラル、サンプリング11.025kにしてみたらプレイ動画に似た感じになった。
ずいぶん感じが変わるもんだ。棒読み関係も音質下げが原因らしいが、なんだか納得。

敵弾の発光エフェクトが自機ショットより下に描画されてるっぽい。
発行エフェクトで拡大しちゃう見かけ上の敵弾の大きさを
自機のショットでキャンセルしようという魂胆なんだろうか。
敵弾発光エフェクト→アイテム発光エフェクト→(レンダーモード変更)→アイテム実体→自機攻撃→敵弾とかいったレンダリング順序の都合か。どうでもいいか。
360版赤い刀だと自機ショットの上どころか自機の上にも発光エフェクトがかかってるようだ。
アイテム→自機ショット→自機→敵弾発光エフェクト→敵弾の順で描画してる様子。
敵弾をアイテムに変換したときに、
ロケテ版だとアイテム出現時間が各々ランダム時間経過後だったが、
同一フレーム中になってた。状況によるかもしれない。
キャラクタがしゃべってる間、INSERTCOINの表記のところに顔アイコンが表示されるみたいな。
口パクもしてるっぽいからなかなか芸が細かい。

/** 追記 */
発光エフェクトレンダリング順序に関しては勘違いのようで、自機より上にきっちり描画されてるみたい。
自信満々のミス! 
自機が死ぬと弾の発光エフェクトが描画されなくなる。
自機処理部分に書いてる…… とは思いにくいが復活待ち中の処理落ち防止? 
気が付くのに時間がかかったが、自機の周囲の敵弾にだけエフェクトがかかるようだ。
最初は発射されていくらか時間がたつとエフェクトがかかるのかとおもってたが、
ボス戦で横のほうに飛んでいくたまにはいつまでもエフェクトがかからない。
理屈の上では自機の周囲に敵弾が多いほど処理落ちすることになるが。

アイテムのオーラはハイパーしてたらつかない。
通常状態だとオーラがつく。だと思う。

 二人プレイの場合、回収する機体がハイパーだとアイテム光らないみたい。
片方だけハイパー状態で回収すると、光るのと光らないがそれぞれ回収される。
 また弾が光るのは2Pの自機の周りのみのよう。
1Pのほうが上に描画されるから処理順として2P→1Pの順なんだろう。




●オンライン販売「嗚呼系弩学園 ケイ部 新入部員募集♪」概要
4月20日(金)12:00 ~ 4月22日(日)23:59
※但し予定数量が完売した時点で、終了となります。

その他、注意事項や商品の概要はショップページをご覧ください。
http://www.cave-shop.jp/

http://www.cave-shop.jp/

32bitDIBから無圧縮AVIファイル

AVIFileCreateStreamで作成してもいいですが、
あらかじめ動画の長さを指定する必要があったりと地味に使いづらい部分があったりするので、
自力でAVI出力することで好き勝手しようという趣旨です。
もっともAVI1.0フォーマットの都合上2GB以上は記録できない(オーバーフローするため)
ということになってるので注意が必要。


ソースコード
size: 42KB



このような動画が出力されます。



AVIRecorder2 avi;
avi.create( fileName, width, height, fps );
avi.update( dib32Image );
...
avi.close();

といった感じに使います。
好きなタイミングでclose()すれば、update()回数分のフレーム数のAVIファイルを作成できます。


■AVIファイルフォーマット
RIFF - AVI (fileSize - 8)
├─LIST - hdrl (200 byte)
│ ├─avih (56 byte)
│ │ ├─dwMicroSecPerFrame
│ │ ├─dwMaxBytesPerSec
│ │ ├─dwPaddingGranularity
│ │ ├─dwFlags
│ │ ├─dwTotalFrames
│ │ ├─dwInitialFrames
│ │ ├─dwSuggestedBufferSize
│ │ ├─dwWidth
│ │ ├─dwHeight
│ │ └─dwReserved[4]
│ │
│ ├─LIST - strl (124 byte)
│ │ ├─strh (64 byte)
│ │ │ ├─fccType
│ │ │ ├─fccHeader
│ │ │ ├─dwFlags
│ │ │ ├─dwPriority
│ │ │ ├─dwLanguage
│ │ │ ├─dwInitialFrames
│ │ │ ├─dwScale
│ │ │ ├─dwRate
│ │ │ ├─dwStart
│ │ │ ├─dwLength
│ │ │ ├─dwSuggestedBufferSize
│ │ │ ├─dwQuality
│ │ │ ├─dwSampleSize
│ │ │ └─rcFrame
│ │ │
│ │ └─strf (40 byte)
│ │   ├─biSize
│ │   ├─biWidth
│ │   ├─biHeight
│ │   ├─biPlanes
│ │   ├─biBitCount
│ │   ├─biSizeImage
│ │   ├─biXPelsPerMeter
│ │   ├─biYPelsPerMeter
│ │   ├─biClrUsed
│ │   └─biClrImportant
│ │
│ └JUNK (1808 byte)

├ LIST - movi
│ ├00db
│ ├00db
│ └00db...

└idx1



以下プログラム。
#include <windows.h>
#include <vfw.h>
#include <algorithm>
 
 
 
const int WINDOW_WIDTH = 640;
const int WINDOW_HEIGHT = 480;
const int TIMER_ID = 1000;
const int FPS = 30;
 
 
 
class DIB32
{
public:
  /**
   * Point
   */
  struct Point
  {
    LONG x, y;
    LONG u, v;
 
    void set( LONG x, LONG y, LONG u, LONG v )
    {
      this->x = x;
      this->y = y;
      this->u = u;
      this->v = v;
    }
  };
 
  class PutColorAdd
  {
  public:
    static inline void update( DWORD& dest, DWORD src )
    {
      DWORD color = (dest & 0x00fefefe) + (src & 0x00fefefe);
      DWORD mask = color & 0x01010100;
      dest = (dest&0xFF000000) | color | (mask - (mask >> 8));
    }
  };
 
 
 
 
  DIB32()
    : m_pixel( NULL )
  {
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  virtual ~DIB32()
  {
    release();
  }
 
  virtual bool create( LONG width, LONG height )
  {
    if ( width <= 0 || height <= 0 ) return false;
    release();
 
    m_pixel = new DWORD[ width * height ];
    if ( !m_pixel ) return false;
 
    m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    m_bmi.bmiHeader.biWidth = width;
    m_bmi.bmiHeader.biHeight = height;
    m_bmi.bmiHeader.biPlanes = 1;
    m_bmi.bmiHeader.biBitCount = 32;
    m_bmi.bmiHeader.biSizeImage = width * height * 4;
    m_bmi.bmiHeader.biCompression = BI_RGB;
    m_bmi.bmiHeader.biXPelsPerMeter = 3780;  //96dpiだと3780らしい。0の場合もあるとのこと
    m_bmi.bmiHeader.biYPelsPerMeter = 3780;
 
    return true;
  }
 
  /** create from HBITMAP */
  bool create( LPCTSTR fileName )
  {
    HBITMAP hBmp = static_cast<HBITMAP>( LoadImage( NULL, fileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE ) );
    if ( !hBmp ) return false;
 
    BITMAP bm = {0};
    GetObject( hBmp, sizeof(BITMAP), &bm );
 
    // create DC
    HDC hdc = CreateCompatibleDC( NULL );
    if ( !hdc ) return false;
 
    // create buf
    if ( !create( bm.bmWidth, bm.bmHeight ) )
    {
      DeleteDC( hdc );
      return false;
    }
 
    // copy
    GetDIBits( hdc, hBmp, 0, bm.bmHeight, m_pixel, &m_bmi, DIB_RGB_COLORS );
 
    DeleteDC( hdc );
    DeleteObject( hBmp );
 
    return true;
  }
 
  virtual void release()
  {
    if ( m_pixel )
    {
      delete [] m_pixel;
      m_pixel = NULL;
    }
    ZeroMemory( &m_bmi, sizeof(m_bmi) );
  }
 
  bool render( HDC hdc, HWND hWnd ) const
  {
    RECT rect;
    GetClientRect( hWnd, &rect );
    return GDI_ERROR != StretchDIBits(
      hdc, 0, 0, rect.right, rect.bottom,
      0, 0, getWidth(), getHeight(),
      m_pixel, &m_bmi, DIB_RGB_COLORS, SRCCOPY );
  }
 
 
 
  template < class T >
  inline void renderLine(
    LPDWORD destLine,
    LONG destMaxWidth,
    LONG startX, LONG endX,
    float startU, float startV,
    float endU, float endV )
  {
    if ( startX > endX )
    {
      std::swap( startX, endX );
      std::swap( startU, endU );
      std::swap( startV, endV );
    }
 
    if ( startX > destMaxWidth || endX < 0 || (endX-startX)==0 ) return;
 
    const float addU = (endU-startU) / static_cast<float>(endX - startX);
    const float addV = (endV-startV) / static_cast<float>(endX - startX);
 
    // cliping-left
    if ( startX < 0 )
    {
      startU += (addU * static_cast<float>(-startX));
      startV += (addV * static_cast<float>(-startX));
      startX = 0;
    }
    // cliping-right
    if ( endX > destMaxWidth )
    {
      endX = destMaxWidth;
    }
 
    float u = startU;
    float v = startV;
    for (LONG x=startX; x<endX; x++)
    {      
      T::update( *(destLine + x), getPixel(static_cast<LONG>(u), static_cast<LONG>(v)) );
 
      u += addU;
      v += addV;
    }
  }
 
  template < class T >
  bool triangle( DIB32& dest, const Point& point1, const Point& point2, const Point& point3 )
  {
    Point p1( point1 ), p2( point2 ), p3( point3 );
 
    // 手動ソート
    if ( p1.y > p2.y ) std::swap( p1, p2 );
    if ( p1.y > p3.y ) std::swap( p1, p3 );
    if ( p2.y > p3.y ) std::swap( p2, p3 );
 
    const float height1_2 = static_cast<float>( p2.y-p1.y ? p2.y-p1.y : 1 );
    const float height1_3 = static_cast<float>( p3.y-p1.y ? p3.y-p1.y : 1 );
    const float height2_3 = static_cast<float>( p3.y-p2.y ? p3.y-p2.y : 1 );
    
    const float destAddX1_2 = static_cast<float>(p2.x-p1.x) / height1_2;
    const float destAddX1_3 = static_cast<float>(p3.x-p1.x) / height1_3;
    const float destAddX2_3 = static_cast<float>(p3.x-p2.x) / height2_3;
    
    const float addU1_2 = static_cast<float>(p2.u-p1.u) / height1_2;
    const float addU1_3 = static_cast<float>(p3.u-p1.u) / height1_3;
    const float addU2_3 = static_cast<float>(p3.u-p2.u) / height2_3;
    const float addV1_2 = static_cast<float>(p2.v-p1.v) / height1_2;
    const float addV1_3 = static_cast<float>(p3.v-p1.v) / height1_3;
    const float addV2_3 = static_cast<float>(p3.v-p2.v) / height2_3;
    
    // 1~2
    float startX = static_cast<float>( p1.x );
    float endX = static_cast<float>( p1.x );
    float startU = static_cast<float>( p1.u );
    float startV = static_cast<float>( p1.v );
    float endU = static_cast<float>( p1.u );
    float endV = static_cast<float>( p1.v );
    LPDWORD destLine = dest.getPixelAddr( 0, p1.y );
 
    for (LONG y=p1.y; y<p2.y&&y<dest.getHeight(); y++)
    {
      // render line
      if ( y >= 0 )
      {
        renderLine<T>( destLine, dest.getWidth(), static_cast<LONG>(startX), static_cast<LONG>(endX), startU, startV, endU, endV );
      }
 
      startX += destAddX1_2;
      endX += destAddX1_3;
      startU += addU1_2;
      endU += addU1_3;
      startV += addV1_2;
      endV += addV1_3;
 
      destLine -= dest.getWidth();
    }
    // 2~3
    startX = static_cast<float>( p2.x );
    startU = static_cast<float>( p2.u );
    startV = static_cast<float>( p2.v );
    for (LONG y=p2.y; y<p3.y&&y<dest.getHeight(); ++y)
    {
      if ( y >= 0 )
      {
        renderLine<T>( destLine, dest.getWidth(), static_cast<LONG>(startX), static_cast<LONG>(endX), startU, startV, endU, endV );
      }
 
      startX += destAddX2_3;
      endX += destAddX1_3;
      startU += addU2_3;
      endU += addU1_3;
      startV += addV2_3;
      endV += addV1_3;
 
      destLine -= dest.getWidth();
    }
 
    return true;
  }
 
  
  LONG getWidth() const { return m_bmi.bmiHeader.biWidth; }
  LONG getHeight() const { return m_bmi.bmiHeader.biHeight; }
  const LPDWORD getPixelAddr() const { return m_pixel; }
  const LPDWORD getPixelAddr( LONG x, LONG y ) const { return m_pixel + ((getHeight()-1)-y)*getWidth() + x; }
  LPDWORD getPixelAddr() { return m_pixel; }
  LPDWORD getPixelAddr( LONG x, LONG y ) { return const_cast<LPDWORD>(static_cast<const DIB32&>(*this).getPixelAddr(x, y)); }
 
  DWORD getPixel( LONG x, LONG y ) const
  {
    if ( x >= 0 && x < getWidth() && y >= 0 && y < getHeight() )
    {
      return *getPixelAddr( x, y );
    }
    return 0;
  }
  
 
protected:
  LPDWORD m_pixel;
  BITMAPINFO m_bmi;
};
 
 
 
class AVIRecorder2
{
public:
#pragma pack(push, 2)
  struct LIST
  {
    DWORD dwList;
    DWORD dwSize;
    DWORD dwForrCC;
  };
 
  struct CHUNK
  {
    DWORD dwFourCC;
    DWORD dwSize;
  };
 
 
  struct Header
  {
    LIST aviList;
    LIST hdrlList;
    CHUNK avih;
    MainAVIHeader mainAVIHeader;
    LIST strlList;
    CHUNK strh;
    AVIStreamHeader streamHeader;
    CHUNK strf;
    BITMAPINFOHEADER streamFormat;
    CHUNK junk;
    BYTE junkData[ 2048 - 240 ];  // moveList含めて2048Byteになるように調整。240=sizeof(Header)-sizeof(junkData)
 
    LIST moviList;
 
    void setData( DWORD width, DWORD height, DWORD fps = 60, DWORD frame = 0 )
    {
      ZeroMemory( this, sizeof(*this) );
 
      aviList.dwList = mmioFOURCC('R','I','F','F');
      aviList.dwSize = 2048-8 + (sizeof(CHUNK)+width*height*4)*frame + sizeof(CHUNK) + sizeof(AVIINDEXENTRY)*frame;
      aviList.dwForrCC = mmioFOURCC('A','V','I',' ');
 
      hdrlList.dwList = mmioFOURCC('L','I','S','T');
      hdrlList.dwSize = 4 + sizeof(avih) + sizeof(mainAVIHeader) + 
        sizeof(strlList) + sizeof(strh) + sizeof(streamHeader) + sizeof(strf) + sizeof(streamFormat);
      hdrlList.dwForrCC = mmioFOURCC('h','d','r','l');
 
      avih.dwFourCC = mmioFOURCC('a','v','i','h');
      avih.dwSize = sizeof(mainAVIHeader);
 
      mainAVIHeader.dwMicroSecPerFrame = 1000000 / fps;
      mainAVIHeader.dwMaxBytesPerSec = width*height*4*fps;
      mainAVIHeader.dwPaddingGranularity = 0;
      mainAVIHeader.dwFlags = 2064;
      mainAVIHeader.dwTotalFrames = frame;
      mainAVIHeader.dwInitialFrames = 0;
      mainAVIHeader.dwStreams = 1;
      mainAVIHeader.dwSuggestedBufferSize = width * height * 4 + sizeof(CHUNK);
      mainAVIHeader.dwWidth = width;
      mainAVIHeader.dwHeight = height;
 
      strlList.dwList = mmioFOURCC('L','I','S','T');
      strlList.dwSize = 4 + sizeof(strh) + sizeof(streamHeader) + sizeof(strf) + sizeof(streamFormat);
      strlList.dwForrCC = mmioFOURCC('s','t','r','l');
 
      strh.dwFourCC = mmioFOURCC('s','t','r','h');
      strh.dwSize = sizeof(streamHeader);
 
      streamHeader.fccType = mmioFOURCC('v','i','d','s');
      streamHeader.fccHandler = mmioFOURCC('D','I','B',' ');
      streamHeader.dwFlags = 0;
      streamHeader.wPriority = 0;
      streamHeader.wLanguage = 0;
      streamHeader.dwInitialFrames = 0;
      streamHeader.dwScale = 1;
      streamHeader.dwRate = fps;
      streamHeader.dwStart = 0;
      streamHeader.dwLength = frame;
      streamHeader.dwSuggestedBufferSize = width * height * 4 + sizeof(CHUNK);
      streamHeader.dwQuality = -1;
      streamHeader.dwSampleSize = width * height * 4;
 
      strf.dwFourCC = mmioFOURCC('s','t','r','f');
      strf.dwSize = sizeof(streamFormat);
 
      streamFormat.biSize = sizeof(streamFormat);
      streamFormat.biWidth = width;
      streamFormat.biHeight = height;
      streamFormat.biPlanes = 1;
      streamFormat.biBitCount = 32;
      streamFormat.biCompression = 0;
      streamFormat.biSizeImage = width * height * 4;
      streamFormat.biXPelsPerMeter = 3780;
      streamFormat.biYPelsPerMeter = 3780;
      streamFormat.biClrUsed = 0;
      streamFormat.biClrImportant = 0;
 
      junk.dwFourCC = mmioFOURCC('J','U','N','K');
      junk.dwSize = sizeof(junkData);
 
      moviList.dwList = mmioFOURCC('L','I','S','T');
      moviList.dwSize = 4 + sizeof(CHUNK)*frame + width*height*4*frame;
      moviList.dwForrCC = mmioFOURCC('m','o','v','i');
    }
  };
#pragma pack(pop)
 
  /** constructor */
  AVIRecorder2()
    : m_file( INVALID_HANDLE_VALUE )
    , m_frame( 0 )
    , m_width( 320 )
    , m_height( 240 )
    , m_fps( 60 )
  {
  }
 
  /** desturctor */
  ~AVIRecorder2()
  {
    clear();
  }
 
  void clear()
  {
    close();
    m_frame = 0;
    m_fps = 60;
    m_width = 320;
    m_height = 240;
  }
 
  /** isOpen */
  bool isOpen() const { return m_file!=INVALID_HANDLE_VALUE; }
 
  /** create */
  bool create( LPCTSTR fileName, DWORD width, DWORD height, DWORD fps )
  {
    m_file = CreateFile( fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
    if ( isOpen() )
    {
      m_width = width;
      m_height = height;
      m_fps = fps;
 
      Header header;
      header.setData( width, height );
 
      DWORD writeSize;
      WriteFile( m_file, &header, sizeof(header), &writeSize, NULL );
 
      return true;
    }
 
    return false;
  }
 
  void update( const DIB32& image )
  {
    if ( isOpen() )
    {
      CHUNK chunk;
      chunk.dwFourCC = mmioFOURCC('0','0','d','b');
      chunk.dwSize = m_width * m_height * 4;
 
      DWORD writeSize;
      WriteFile( m_file, &chunk, sizeof(chunk), &writeSize, NULL );
      WriteFile( m_file, const_cast<LPDWORD>(image.getPixelAddr()), chunk.dwSize, &writeSize, NULL );
 
      m_frame++;
    }
  }
 
  /** close */
  void close()
  {
    if ( isOpen() )
    {
      DWORD writeSize;
 
      // write index header
      CHUNK index;
      index.dwFourCC = mmioFOURCC('i','d','x','1');
      index.dwSize = sizeof(AVIINDEXENTRY) * m_frame;      
      WriteFile( m_file, &index, sizeof(index), &writeSize, NULL );
 
      // write index chunks
      AVIINDEXENTRY entry;
      entry.ckid = mmioFOURCC('0','0','d','b');
      entry.dwFlags = AVIIF_KEYFRAME;
      entry.dwChunkLength = m_width * m_height * 4;
      for (DWORD i=0; i<m_frame; ++i)
      {
        entry.dwChunkOffset = 4 + sizeof(CHUNK)*i + m_width*m_height*4*i;
        WriteFile( m_file, &entry, sizeof(entry), &writeSize, NULL );
      }
 
      // write header again
      SetFilePointer( m_file, 0, NULL, FILE_BEGIN );
      Header header;
      header.setData( m_width, m_height, m_fps, m_frame );
      WriteFile( m_file, &header, sizeof(header), &writeSize, NULL );
 
      // close
      CloseHandle( m_file );
      m_file = NULL;
    }
  }
 
private:
  HANDLE m_file;
  DWORD m_frame;
  DWORD m_width, m_height, m_fps;
};
 
 
 
struct ObjPoint
{
  float x, y, vx, vy;
};
 
 
 
LRESULT CALLBACK wndProc(
  HWND hWnd,
  UINT msg,
  WPARAM wParam,
  LPARAM lParam )
{
  static DIB32 back, image;
  static ObjPoint point[ 4 ];
  static AVIRecorder2 avi;
  switch (msg)
  {
  case WM_DESTROY:
    avi.close();
    ShowWindow( hWnd, SW_HIDE );
    PostQuitMessage(0);
    break;
  case WM_CREATE:
    back.create( WINDOW_WIDTH, WINDOW_HEIGHT );
    image.create( TEXT("image.bmp") );
 
    point[0].x = 100;
    point[0].y = 100;
    point[1].x = 100;
    point[1].y = 200;
    point[2].x = 200;
    point[2].y = 100;
    point[3].x = 200;
    point[3].y = 200;
    srand( GetTickCount() );
    for (int i=0; i<4; ++i)
    {
      point[i].vx = (static_cast<float>( std::rand() & 1023 ) / 1023.f) * 32 - 16;
      point[i].vy = (static_cast<float>( std::rand() & 1023 ) / 1023.f) * 32 - 16;
    }
    avi.create( TEXT("output.avi"), back.getWidth(), back.getHeight(), FPS );
    break;
  case WM_PAINT:
    {
      PAINTSTRUCT ps = {0};
      HDC hdc = BeginPaint( hWnd, &ps );
      back.render( hdc, hWnd );
      EndPaint( hWnd, &ps );
    }
    break;
  case WM_TIMER:
    ZeroMemory( back.getPixelAddr(), back.getWidth() * back.getHeight() * 4 );
    for (int i=0; i<4; ++i)
    {
      point[i].x += point[i].vx;
      point[i].y += point[i].vy;
      if ( point[i].x < 0 || point[i].x > WINDOW_WIDTH ) point[i].vx = -point[i].vx;
      if ( point[i].y < 0 || point[i].y > WINDOW_HEIGHT ) point[i].vy = -point[i].vy;
    }
 
    {
      DIB32::Point p1, p2, p3, p4;
      p1.x = point[0].x;
      p1.y = point[0].y;
      p1.u = 0;
      p1.v = 0;
      p2.x = point[1].x;
      p2.y = point[1].y;
      p2.u = 0;
      p2.v = 32;
      p3.x = point[2].x;
      p3.y = point[2].y;
      p3.u = 32;
      p3.v = 0;
      p4.x = point[3].x;
      p4.y = point[3].y;
      p4.u = 32;
      p4.v = 32;
      image.triangle< DIB32::PutColorAdd >( back, p1, p2, p3 );
      image.triangle< DIB32::PutColorAdd >( back, p2, p3, p4 );
 
      InvalidateRect( hWnd, NULL, FALSE );
      avi.update( back );
    }
 
    break;
  default:
    return DefWindowProc( hWnd, msg, wParam, lParam );
  }
 
  return 0;
}
 
 
 
int WINAPI WinMain(
  HINSTANCE hInstance,
  HINSTANCE, PSTR, int )
{
  LPCTSTR WINDOW_NAME = TEXT("sample");
 
  WNDCLASSEX wc;
  wc.style    = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc  = reinterpret_cast<WNDPROC>( wndProc );
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.cbSize    = sizeof( WNDCLASSEX );
  wc.hInstance  = hInstance;
  wc.hIcon    = NULL;
  wc.hIconSm    = NULL;
  wc.hCursor    = LoadCursor( NULL, IDC_ARROW );
  wc.hbrBackground= reinterpret_cast<HBRUSH>( GetStockObject(WHITE_BRUSH) );
  wc.lpszMenuName  = NULL;
  wc.lpszClassName= WINDOW_NAME;
  if ( !RegisterClassEx(&wc) ) return 0;
 
  LONG winWidth = WINDOW_WIDTH
    + GetSystemMetrics(SM_CXEDGE)
    + GetSystemMetrics(SM_CXBORDER)
    + GetSystemMetrics(SM_CXDLGFRAME);
  LONG winHeight = WINDOW_HEIGHT
    + GetSystemMetrics(SM_CYEDGE)
    + GetSystemMetrics(SM_CYBORDER)
    + GetSystemMetrics(SM_CYDLGFRAME)
    + GetSystemMetrics(SM_CYCAPTION);
  HWND hWnd = CreateWindowEx(
    0, WINDOW_NAME, NULL, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
    CW_USEDEFAULT, CW_USEDEFAULT, winWidth, winHeight,
    NULL, NULL, hInstance, NULL);
  if ( !hWnd ) return -1;
 
  ShowWindow( hWnd, SW_SHOWNORMAL );
  UpdateWindow( hWnd );
 
  SetTimer( hWnd, TIMER_ID, 1000/FPS, NULL );
  
  MSG msg;
  for (;;)
  {
    if ( !GetMessage(&msg, NULL, 0, 0) ) break;
    TranslateMessage( &msg );
    DispatchMessage( &msg );
  }
 
 
  UnregisterClass( WINDOW_NAME, hInstance );
  return msg.wParam;
}


640x480なら30秒程度で2GBに達する。
ゲームのPV程度なら30秒も回さないからこれでも十分ではある。
2GB以上保存可能な、AVI2.0のフォーマットを勉強中ではあるのだけど
肝心のAVI2.0の動画ファイルが手に入らないので実態が不明瞭で困っている。
仕様通りに作ると動かないらしいが。

2012年4月7日土曜日

日記ちゃんみみこぴ


untitled61cp.mp3
size: 3.39MB
 
 最大往生1面の耳コピ。
動画から耳コピしたので、がっちり聞こえるのがメロディぐらい。
聞き直すと恐ろしく間違ってるが、それもまたよし。
FLStudio10Trial + Synth1にて
 今月末稼働予定で楽しみ。

 
 ここ数回ケーキを焼くのに失敗してたのだけど、
今回、バターをさらさらに溶かして、割と熱い状態で生地に混ぜたらうまくいった。
バターが固形化しかかってるとかなり失敗率が高いようだ。