チュートリアル - ビットマップ ペイント ツールの開発 - ロードと保存

チュートリアル > ビットマップ ペイント ツールの開発 - ロードと保存

このビットマップ ペイント ツール開発の手順では、[新規](New)、[開く](Open)、[保存](Save)のオプションが含まれるメイン メニュー バーを追加します。

全体の流れ:

いくつかのメニュー項目と、対応するイベント ハンドラを持つ新しい右クリック メニューを定義します。

右クリック メニューをダイアログ ボックスにメニュー バーとして割り当てます。

スクリプト:

macroScript MicroPaint category: "HowTo"
(
global MicroPaint_CanvasRollout
try(destroyDialog MicroPaint_CanvasRollout) catch()
local isDrawing = false
local bitmapX = bitmapY = 512
local theCanvasBitmap = bitmap bitmapX bitmapY color:white
local theBackgroundBitmap = bitmap bitmapX bitmapY color:white
local currentPos = lastPos = [0,0]
 
--NEW MENU CODE STARTS HERE
rcMenu CanvasMenu
(
  subMenu"File"
  (
    menuItem new_menu "New"
    menuItem open_menu "Open..."
    menuItem save_as "Save As..."
    separator file_menu_1
    menuItem quit_tool "Quit"  
  )
  subMenu "Edit"( )
  subMenu "Help"
  (
    menuItem about_tool "About MicroPaint..." 
  )
 
  on new_menu picked do
  (
    theBackgroundBitmap = theCanvasBitmap = bitmap bitmapX bitmapY color:MicroPaint_CanvasRollout.paperColor.color
    MicroPaint_CanvasRollout.theCanvas.bitmap = theCanvasBitmap
  ) 
 
  on open_menu picked do
  (
    theOpenBitmap= selectBitmap()
    if theOpenBitmap != undefined do
    (
      copy theOpenBitmap theCanvasBitmap
      copy theOpenBitmap theBackgroundBitmap
      close theOpenBitmap
      MicroPaint_CanvasRollout.theCanvas.bitmap = theCanvasBitmap
    )
  )
 
  on save_as picked do
  (
    theSaveName = getSaveFileName types:"BMP (*.bmp)|*.bmp|Targa (rotation*.tga)|*.tga|JPEG (*.jpg)|*.jpg"
    if theSaveName != undefined do
    (
      theCanvasBitmap.filename = theSaveName
      save theCanvasBitmap
    )
  )
  on about_tool picked do messagebox "MicroPaint\nMAXScript Tutorial" title:"About..."
  on quit_tool picked do destroyDialog MicroPaint_CanvasRollout
)
--NEW MENU CODEENDHERE
 
rollout MicroPaint_CanvasRollout "MicroPaint"
(
  bitmap theCanvas pos:[0,0] width:bitmapX height:bitmapY bitmap:theCanvasBitmap
  colorpicker inkColor height:16 modal:false color:black across:5
  colorpicker paperColor height:16 modal:false color:white
  checkbutton airBrush "AirBrush" width:50
  spinner AirBrushSpeed "Speed" range:[0.1,50,10] fieldwidth:30
  spinner BrushSize "Size"range:[1,50,10] type:#integer fieldwidth:40
  listbox BrushShape items:#("Circle","Box","Circle Smooth") pos:[bitmapX+5,0] width:90
 
  fn paintBrush pos =
  (
    case BrushShape.selection of
    (
      1: (
        if distance pos currentPos <= BrushSize.value/2 do
          setPixels theCanvasBitmap pos #(inkColor.color)
      )
      2: setPixels theCanvasBitmap pos #(inkColor.color)
      3: (
        theFactor = (distance pos currentPos) / (BrushSize.value/2.0)
        if theFactor <= 1.0 do
        (
          theFactor = sin ( 90.0 * theFactor)
          thePixels = getPixels theCanvasBitmap pos 1
          if thePixels[1] != undefined do
          (
            thePixels[1] = (thePixels[1] * theFactor) + (inkColor.color * (1.0 - theFactor))
            setPixels theCanvasBitmap pos thePixels
          )
        )
      )--end case 3
    )--end case
  )--end fn
 
  fn drawStroke lastPos pos =
  (
    currentPos = lastPos
    deltaX = pos.x - lastPos.x
    deltaY = pos.y - lastPos.y
    maxSteps = amax #(abs(deltaX),abs(deltaY))
    deltaStepX = deltaX / maxSteps
    deltaStepY = deltaY / maxSteps
    for i = 0 to maxSteps do
    (
      if airBrush.checked then
      (
        for b = 1 to (BrushSize.value / AirBrushSpeed.value) do
          paintBrush (currentPos + (random [-BrushSize.value/2,-BrushSize.value/2] [BrushSize.value/2,BrushSize.value/2] ))
      )
      else
        for b = -BrushSize.value/2 to BrushSize.value/2 do
          for c = -BrushSize.value/2 to BrushSize.value/2 do
            paintBrush (currentPos + [c,b])
      currentPos += [deltaStepX, deltaStepY]
    )
    theCanvas.bitmap = theCanvasBitmap
  )
 
  on MicroPaint_CanvasRollout lbuttondown pos do
  (
    lastPos = pos
    isDrawing = true
    drawStroke lastPos pos
  )
  on MicroPaint_CanvasRollout lbuttonup pos do isDrawing = false
  on MicroPaint_CanvasRollout mousemove pos do
  (
    if isDrawing do drawStroke lastPos pos
    lastPos = pos
  )
)
createDialog MicroPaint_CanvasRollout (bitmapx+100) (bitmapy+30) menu:CanvasMenu
MicroPaint_CanvasRollout.theCanvas.bitmap = theBackgroundBitmap
)

ステップごとの解説

--Code in italic has no changes since the previous version.

macroScript MicroPaint category:"HowTo"
(
global MicroPaint_CanvasRollout
try(destroyDialog MicroPaint_CanvasRollout)catch()
local isDrawing = false
local bitmapX = bitmapY = 512
local theCanvasBitmap = bitmap bitmapX bitmapY color:white

local theBackgroundBitmap = bitmap bitmapX bitmapY color:white 

バックグラウンドという 2 つ目のビットマップを定義します。今回はまだ使用しませんが、次のチュートリアルで消去関数を使用するときに必要になります。

local currentPos = lastPos = [0,0]

rcMenu CanvasMenu (

右クリック メニューの定義です。

RCMenu ユーザ インタフェース項目

subMenu "File" (

メニューの最初の項目を[ファイル](File)と呼びます。一般的なプログラムではメイン メニューに[ファイル](File)、[編集](Edit)、[ヘルプ](Help)の項目が用意されています。これらの項目も後で定義します。

menuItem new_menu "New"
menuItem open_menu "Open..."
menuItem save_as "Save As..."

[ファイル](File)メニュー内に、新しい描画を開始するメニュー項目、既存の描画を開くメニュー項目、作業結果をディスク上のファイルに保存するメニュー項目を追加します。

separator file_menu_1

メニュー項目の間に横線を引くセパレータです。

menuItem quit_tool "Quit"  

このメニュー項目は、ツールの終了に使用します。

)
subMenu "Edit" ( )

[編集](Edit)メニューは、この時点ではまだ何もない状態のままにしておきます。

subMenu "Help"
(
menuItem about_tool "About MicroPaint..." 
)

[ヘルプ](Help)メニューには[About]の項目だけを入れます。

on new_menu picked do
(

これは、メニュー項目[ファイル](File) > [新規](New)のイベント ハンドラです。ユーザがこのメニュー項目をメニューから選択した場合、

RCMenu 句

theBackgroundBitmap = theCanvasBitmap = bitmap bitmapX bitmapY color:MicroPaint_CanvasRollout.paperColor.color

新しくユーザ インタフェースに追加したペーパー カラー (バックグラウンド カラー) を使用してビットマップを定義し、それをペイントのキャンバスと新しいバックグラウンド ビットマップに割り当てます。

MicroPaint_CanvasRollout.theCanvas.bitmap = theCanvasBitmap

次に、その結果をユーザ インタフェースのビットマップに割り当てます。

)
on open_menu picked do
(

これは、メニュー項目[ファイル](File) > [開く](Open)のイベント ハンドラです。ユーザがこのメニュー項目をメニューから選択した場合、

theOpenBitmap= selectBitmap()

3ds Max の標準のビットマップ選択ダイアログ ボックスを開きます。サポートされているすべてのファイル形式を表示できるオプションもあります。

if theOpenBitmap != undefined do
(

ユーザが有効なビットマップを選択した後、操作をキャンセルしない場合は、

copy theOpenBitmap theCanvasBitmap

開かれたビットマップをペイントのキャンバスにコピーします。

copy theOpenBitmap theBackgroundBitmap

また、バックグラウンドのビットマップにもコピーします。copy メソッドでは、キャンバスのサイズに合わせてオリジナルのビットマップのサイズを変更します。

close theOpenBitmap

最後に、開いたビットマップを閉じます。

MicroPaint_CanvasRollout.theCanvas.bitmap = theCanvasBitmap

そして、ペイントのキャンバスをユーザ インタフェースのビットマップに割り当てます。

)
)

on save_as picked do
(

これは、メニュー項目[ファイル](File) > [名前を付けて保存](Save As)のイベント ハンドラです。ユーザがこのメニュー項目をメニューから選択した場合、

theSaveName = getSaveFileName types:"BMP (*.bmp)|*.bmp|Targa (*.tga)|*.tga|JPEG (*.jpg)|*.jpg"

3ds Max の標準のファイル保存ダイアログ ボックスを開き、ファイル拡張子の一覧を表示します。RLA、RPF など、サポートされているファイル形式であればどれでもこのリストに追加できます。

if theSaveName != undefined do
(

ユーザが有効な名前を指定した後、操作をキャンセルしない場合は、

theCanvasBitmap.filename = theSaveName

ペイントのキャンバスのファイル名を指定された名前に設定し、

save theCanvasBitmap

ビットマップをディスクに保存します。

)
)
on about_tool picked do messagebox "MicroPaint\nMAXScript Tutorial" title:"About..."

ユーザがメニュー項目の[ヘルプ](Help) > [About]を選択した場合、テキストを含むメッセージ ボックスを開きます。このダイアログ ボックスにはバージョン番号などのテキストを入れることができます。

on quit_tool picked do destroyDialog MicroPaint_CanvasRollout

ユーザがメニュー項目の[ファイル](File) > [Quit]を選択した場合、ダイアログ ボックスを閉じます。後で、現在のペイントをディスクに保存するかどうかを尋ねるメッセージを追加することもできます。

)
 

rollout MicroPaint_CanvasRollout "MicroPaint"
(
bitmap theCanvas pos:[0,0] width:bitmapX height:bitmapY bitmap:theCanvasBitmap
 colorpicker inkColor height:16modal:false color:black across:5 

ペーパー カラー (新しいイメージのバックグラウンド カラー) を追加するには、across: パラメータを 5 に増やす必要があります。

colorpicker paperColor height:16 modal:false color:white

このカラー ピッカーではペーパー カラー(新しいイメージのバックグラウンド カラー)を追加します。カラー ピッカーはモードレスであるため、常に開いている状態にできます。また、カラーをドラッグ アンド ドロップして、インクとペーパーのカラー ピッカー間でカラーをコピーしたり、3ds Max の他の部分からカラーをドラッグ アンド ドロップすることもできます。

checkbutton airBrush "AirBrush" width:50
spinner AirBrushSpeed "Speed" range:[0.1,50,10] fieldwidth:30
spinner BrushSize "Size" range:[1,50,10] type:#integer fieldwidth:40
listbox BrushShape items:#("Circle", "Box", "Circle Smooth") pos:[bitmapX+5,0] width:90

fn paintBrush pos =
(
case BrushShape.selection of
(
1: (
if distance pos currentPos <= BrushSize.value/2 do
setPixels theCanvasBitmap pos #(inkColor.color)
)
2: setPixels theCanvasBitmap pos #(inkColor.color)
3: (
theFactor = (distance pos currentPos) / (BrushSize.value/2.0)
if theFactor <= 1.0 do
(
theFactor = sin ( 90.0 * theFactor)
thePixels = getPixels theCanvasBitmap pos 1
if thePixels[1] != undefined do
(
thePixels[1] = (thePixels[1] * theFactor) + (inkColor.color * (1.0 - theFactor))
setPixels theCanvasBitmap pos thePixels
)
)
)--end case 3
)--end case
)--end fn

fn drawStroke lastPos pos =
(
currentPos = lastPos
deltaX = pos.x - lastPos.x
deltaY = pos.y - lastPos.y
maxSteps = amax #(abs(deltaX),abs(deltaY))
deltaStepX = deltaX / maxSteps
deltaStepY = deltaY / maxSteps
for i = 0 to maxSteps do
(
if airBrush.checked then
(
for b = 1 to (BrushSize.value / AirBrushSpeed.value) do
paintBrush (currentPos + (random [-BrushSize.value/2,-BrushSize.value/2] [BrushSize.value/2,BrushSize.value/2] ))
)
else
for b = -BrushSize.value/2 to BrushSize.value/2 do
for c = -BrushSize.value/2 to BrushSize.value/2 do
paintBrush (currentPos + [c,b])
currentPos += [deltaStepX, deltaStepY]
)
theCanvas.bitmap = theCanvasBitmap
)

on MicroPaint_CanvasRollout lbuttondown pos do
(
lastPos = pos
isDrawing = true
drawStroke lastPos pos
)
on MicroPaint_CanvasRollout lbuttonup pos do isDrawing = false
on MicroPaint_CanvasRollout mousemove pos do
(
if isDrawing do drawStroke lastPos pos
lastPos = pos
)
) createDialog MicroPaint_CanvasRollout (bitmapx+100) (bitmapy+30) menu:CanvasMenu 

スクリプトの最初の方で定義した右クリック メニューをダイアログ ボックスに追加します。

MicroPaint_CanvasRollout.theCanvas.bitmap = theBackgroundBitmap

ツールの起動後、表示をクリアすることをお勧めします。 前回のペイント セッションからの古いバージョンがビットマップに表示されたままになっている可能性があるためです。

)

結果:

前のチュートリアル:

チュートリアル - ビットマップ ペイント ツールの開発 - スムーズ ブラシ

次のチュートリアル:

チュートリアル - ビットマップ ペイント ツールの開発 - 変更の消去

関連事項