home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch9 / Morph.frm (.txt) < prev    next >
Encoding:
Visual Basic Form  |  1999-05-23  |  32.2 KB  |  913 lines

  1. VERSION 5.00
  2. Object = "{F9043C88-F6F2-101A-A3C9-08002B2F49FB}#1.2#0"; "COMDLG32.OCX"
  3. Begin VB.Form frmMorph 
  4.    Caption         =   "Morph [ -> ]"
  5.    ClientHeight    =   3120
  6.    ClientLeft      =   165
  7.    ClientTop       =   735
  8.    ClientWidth     =   6555
  9.    LinkTopic       =   "Form2"
  10.    ScaleHeight     =   3120
  11.    ScaleWidth      =   6555
  12.    StartUpPosition =   3  'Windows Default
  13.    Begin VB.TextBox txtFrames 
  14.       Height          =   285
  15.       Left            =   1080
  16.       TabIndex        =   7
  17.       Text            =   "10"
  18.       Top             =   480
  19.       Width           =   495
  20.    End
  21.    Begin VB.TextBox txtBaseName 
  22.       Height          =   285
  23.       Left            =   1080
  24.       TabIndex        =   5
  25.       Top             =   120
  26.       Width           =   5055
  27.    End
  28.    Begin VB.PictureBox picOriginal 
  29.       AutoSize        =   -1  'True
  30.       Height          =   2010
  31.       Index           =   1
  32.       Left            =   2280
  33.       ScaleHeight     =   130
  34.       ScaleMode       =   3  'Pixel
  35.       ScaleWidth      =   130
  36.       TabIndex        =   3
  37.       Top             =   960
  38.       Width           =   2010
  39.    End
  40.    Begin VB.CommandButton cmdMorph 
  41.       Caption         =   "Morph"
  42.       Height          =   375
  43.       Left            =   1680
  44.       TabIndex        =   2
  45.       Top             =   480
  46.       Width           =   735
  47.    End
  48.    Begin VB.PictureBox picResult 
  49.       Height          =   2010
  50.       Left            =   4440
  51.       ScaleHeight     =   130
  52.       ScaleMode       =   3  'Pixel
  53.       ScaleWidth      =   130
  54.       TabIndex        =   1
  55.       Top             =   960
  56.       Width           =   2010
  57.    End
  58.    Begin MSComDlg.CommonDialog dlgOpenFile 
  59.       Left            =   0
  60.       Top             =   600
  61.       _ExtentX        =   847
  62.       _ExtentY        =   847
  63.       _Version        =   393216
  64.    End
  65.    Begin VB.PictureBox picOriginal 
  66.       AutoSize        =   -1  'True
  67.       Height          =   2010
  68.       Index           =   0
  69.       Left            =   120
  70.       ScaleHeight     =   130
  71.       ScaleMode       =   3  'Pixel
  72.       ScaleWidth      =   130
  73.       TabIndex        =   0
  74.       Top             =   960
  75.       Width           =   2010
  76.    End
  77.    Begin VB.Label Label1 
  78.       Caption         =   "Frames"
  79.       Height          =   255
  80.       Index           =   1
  81.       Left            =   120
  82.       TabIndex        =   6
  83.       Top             =   480
  84.       Width           =   855
  85.    End
  86.    Begin VB.Label Label1 
  87.       Caption         =   "Base Name"
  88.       Height          =   255
  89.       Index           =   0
  90.       Left            =   120
  91.       TabIndex        =   4
  92.       Top             =   120
  93.       Width           =   855
  94.    End
  95.    Begin VB.Menu mnuFile 
  96.       Caption         =   "&File"
  97.       Begin VB.Menu mnuFileOpen 
  98.          Caption         =   "Open File &1..."
  99.          Index           =   0
  100.          Shortcut        =   {F5}
  101.       End
  102.       Begin VB.Menu mnuFileOpen 
  103.          Caption         =   "Open File &2..."
  104.          Index           =   1
  105.          Shortcut        =   {F6}
  106.       End
  107.       Begin VB.Menu mnuFileGridSep 
  108.          Caption         =   "-"
  109.       End
  110.       Begin VB.Menu mnuFileLoadCoordinates 
  111.          Caption         =   "&Load Grid Coordinates..."
  112.          Shortcut        =   ^L
  113.       End
  114.       Begin VB.Menu mnuFileSaveCoordinates 
  115.          Caption         =   "&Save Grid Coordinates..."
  116.          Shortcut        =   ^S
  117.       End
  118.    End
  119.    Begin VB.Menu mnuOpt 
  120.       Caption         =   "&Grids"
  121.       Begin VB.Menu mnuGridReset 
  122.          Caption         =   "&Reset"
  123.          Begin VB.Menu mnuGridResetGrid 
  124.             Caption         =   "&Left"
  125.             Index           =   0
  126.          End
  127.          Begin VB.Menu mnuGridResetGrid 
  128.             Caption         =   "&Right"
  129.             Index           =   1
  130.          End
  131.       End
  132.       Begin VB.Menu mnuGridSwap 
  133.          Caption         =   "&Swap"
  134.       End
  135.       Begin VB.Menu mnuGridCopy 
  136.          Caption         =   "&Copy Grid"
  137.          Begin VB.Menu mnuGridCopyRightToLeft 
  138.             Caption         =   "-->"
  139.          End
  140.          Begin VB.Menu mnuGridCopyLeftToRight 
  141.             Caption         =   "<--"
  142.          End
  143.       End
  144.       Begin VB.Menu mnuGridSym 
  145.          Caption         =   "&Symmetry"
  146.          Begin VB.Menu mnuGridSymLeft 
  147.             Caption         =   "&Left Grid"
  148.             Begin VB.Menu mnuGridSymLeftLeftToRight 
  149.                Caption         =   "-->"
  150.             End
  151.             Begin VB.Menu mnuGridSymLeftRightToLeft 
  152.                Caption         =   "<--"
  153.             End
  154.          End
  155.          Begin VB.Menu mnuGridSymRight 
  156.             Caption         =   "&Right Grid"
  157.             Begin VB.Menu mnuGridSymRightLeftToRight 
  158.                Caption         =   "-->"
  159.             End
  160.             Begin VB.Menu mnuGridSymRightRightToLeft 
  161.                Caption         =   "<--"
  162.             End
  163.          End
  164.       End
  165.    End
  166. Attribute VB_Name = "frmMorph"
  167. Attribute VB_GlobalNameSpace = False
  168. Attribute VB_Creatable = False
  169. Attribute VB_PredeclaredId = True
  170. Attribute VB_Exposed = False
  171. Option Explicit
  172. Private Const NUM_POINTS = 7
  173. Private PointX(0 To 1, 0 To NUM_POINTS + 1, 0 To NUM_POINTS + 1) As Single
  174. Private PointY(0 To 1, 0 To NUM_POINTS + 1, 0 To NUM_POINTS + 1) As Single
  175. Private GridDx As Single
  176. Private GridDy As Single
  177. Private MorphGridX(0 To NUM_POINTS + 1, 0 To NUM_POINTS + 1) As Single
  178. Private MorphGridY(0 To NUM_POINTS + 1, 0 To NUM_POINTS + 1) As Single
  179. Private Dragging As Boolean
  180. Private DragR As Integer
  181. Private DragC As Integer
  182. Private FileTitle(0 To 1) As String
  183. Private Morphing As Boolean
  184. ' Make the grid symmetric by copying its left
  185. ' half to its right half.
  186. Private Sub MakeLeftToRightSymmetric(ByVal Index As Integer)
  187. Dim row As Integer
  188. Dim col As Integer
  189. Dim mid_col As Integer
  190. Dim mid_x As Single
  191.     mid_x = picOriginal(Index).ScaleWidth / 2
  192.     mid_col = (NUM_POINTS + 1) \ 2
  193.     For row = 0 To NUM_POINTS + 1
  194.         For col = 0 To mid_col
  195.             PointX(Index, row, NUM_POINTS + 1 - col) = _
  196.                 mid_x + mid_x - PointX(Index, row, col)
  197.             PointY(Index, row, NUM_POINTS + 1 - col) = _
  198.                 PointY(Index, row, col)
  199.         Next col
  200.     Next row
  201.     ' Redraw the grid.
  202.     DrawGrid Index
  203. End Sub
  204. ' Make the grid symmetric by copying its right
  205. ' half to its left half.
  206. Private Sub MakeRightToLeftSymmetric(ByVal Index As Integer)
  207. Dim row As Integer
  208. Dim col As Integer
  209. Dim mid_col As Integer
  210. Dim mid_x As Single
  211.     mid_x = picOriginal(Index).ScaleWidth / 2
  212.     mid_col = (NUM_POINTS + 1) \ 2
  213.     For row = 0 To NUM_POINTS + 1
  214.         For col = 0 To mid_col
  215.             PointX(Index, row, col) = _
  216.                 mid_x + mid_x - PointX(Index, row, NUM_POINTS + 1 - col)
  217.             PointY(Index, row, col) = _
  218.                 PointY(Index, row, NUM_POINTS + 1 - col)
  219.         Next col
  220.     Next row
  221.     ' Redraw the grid.
  222.     DrawGrid Index
  223. End Sub
  224. ' Using s and t values, return the coordinates of a
  225. ' point in a quadrilateral.
  226. Private Sub STToPoints(ByRef X As Single, ByRef Y As Single, ByVal s As Single, ByVal t As Single, ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, ByVal y2 As Single, ByVal x3 As Single, ByVal y3 As Single, ByVal x4 As Single, ByVal y4 As Single)
  227. Dim xa As Single
  228. Dim ya As Single
  229. Dim xb As Single
  230. Dim yb As Single
  231.     xa = x1 + t * (x2 - x1)
  232.     ya = y1 + t * (y2 - y1)
  233.     xb = x3 + t * (x4 - x3)
  234.     yb = y3 + t * (y4 - y3)
  235.     X = xa + s * (xb - xa)
  236.     Y = ya + s * (yb - ya)
  237. End Sub
  238. ' Find S and T for the point (X, Y) in the
  239. ' quadrilateral with points (x1, y1), (x2, y2),
  240. ' (x3, y3), and (x4, y4). Return True if the point
  241. ' lies within the quadrilateral and False otherwise.
  242. Private Function PointsToST(ByVal X As Single, ByVal Y As Single, ByRef s As Single, ByRef t As Single, ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, ByVal y2 As Single, ByVal x3 As Single, ByVal y3 As Single, ByVal x4 As Single, ByVal y4 As Single) As Boolean
  243. Dim Ax As Single
  244. Dim Bx As Single
  245. Dim Cx As Single
  246. Dim Dx As Single
  247. Dim Ex As Single
  248. Dim Ay As Single
  249. Dim By As Single
  250. Dim Cy As Single
  251. Dim Dy As Single
  252. Dim Ey As Single
  253. Dim a As Single
  254. Dim b As Single
  255. Dim c As Single
  256. Dim det As Single
  257. Dim denom As Single
  258.     Ax = x2 - x1: Ay = y2 - y1
  259.     Bx = x4 - x3: By = y4 - y3
  260.     Cx = x3 - x1: Cy = y3 - y1
  261.     Dx = X - x1: Dy = Y - y1
  262.     Ex = Bx - Ax: Ey = By - Ay
  263.     a = -Ax * Ey + Ay * Ex
  264.     b = Ey * Dx - Dy * Ex + Ay * Cx - Ax * Cy
  265.     c = Dx * Cy - Dy * Cx
  266.     det = b * b - 4 * a * c
  267.     If det >= 0 Then
  268.         If Abs(a) < 0.001 Then
  269.             t = -c / b
  270.         Else
  271.             t = (-b - Sqr(det)) / (2 * a)
  272.         End If
  273.         denom = (Cx + Ex * t)
  274.         If Abs(denom) > 0.001 Then
  275.             s = (Dx - Ax * t) / denom
  276.         Else
  277.             denom = (Cy + Ey * t)
  278.             If Abs(denom) > 0.001 Then
  279.                 s = (Dy - Ay * t) / denom
  280.             Else
  281.                 s = -1
  282.             End If
  283.         End If
  284.         PointsToST = _
  285.             (t >= -0.00001 And t <= 1.00001 And _
  286.              s >= -0.00001 And s <= 1.00001)
  287.     Else
  288.         PointsToST = False
  289.     End If
  290. End Function
  291. ' Arrange the controls.
  292. Private Sub ArrangeControls()
  293.     picOriginal(1).Left = picOriginal(0).Left + picOriginal(0).Width + 60
  294.     picResult.Move picOriginal(1).Left + picOriginal(1).Width + 60, _
  295.         picOriginal(1).Top, picOriginal(0).Width, picOriginal(0).Height
  296.     picResult.Line (0, 0)-(picResult.ScaleWidth, picResult.ScaleHeight), _
  297.         picResult.BackColor, BF
  298.     picResult.Picture = picResult.Image
  299.     Width = picResult.Left + picResult.Width + 120 + Width - ScaleWidth
  300.     Height = picResult.Top + picResult.Height + 120 + Height - ScaleHeight
  301.     txtBaseName.Width = ScaleWidth - txtBaseName.Left - 120
  302. End Sub
  303. ' Copy points from picture fr_index to picture to_index.
  304. Private Sub CopyPoints(ByVal fr_index As Integer, ByVal to_index As Integer)
  305. Dim r As Integer
  306. Dim c As Integer
  307.     ' Copy the points.
  308.     For r = 0 To NUM_POINTS + 1
  309.         For c = 0 To NUM_POINTS + 1
  310.             PointX(to_index, r, c) = PointX(fr_index, r, c)
  311.             PointY(to_index, r, c) = PointY(fr_index, r, c)
  312.         Next c
  313.     Next r
  314.     ' Redraw the grids.
  315.     DrawGrid 0
  316.     DrawGrid 1
  317. End Sub
  318. ' Set the file dialog's filters for graphic files.
  319. Private Sub SetFiltersGraphic()
  320.     dlgOpenFile.Filter = _
  321.         "Bitmaps (*.bmp)|*.bmp|" & _
  322.         "GIFs (*.gif)|*.gif|" & _
  323.         "JPEGs (*.jpg)|*.jpg;*.jpeg|" & _
  324.         "Icons (*.ico)|*.ico|" & _
  325.         "Cursors (*.cur)|*.cur|" & _
  326.         "Run-Length Encoded (*.rle)|*.rle|" & _
  327.         "Metafiles (*.wmf)|*.wmf|" & _
  328.         "Enhanced Metafiles (*.emf)|*.emf|" & _
  329.         "Graphic Files|*.bmp;*.gif;*.jpg;*.jpeg;*.ico;*.cur;*.rle;*.wmf;*.emf|" & _
  330.         "All Files (*.*)|*.*"
  331. End Sub
  332. ' Set the file dialog's filters for text files.
  333. Private Sub SetFiltersText()
  334.     dlgOpenFile.Filter = _
  335.         "Morph Grid Files (*.mor)|*.mor|" & _
  336.         "Text Files (*.txt)|*.txt|" & _
  337.         "All Files (*.*)|*.*"
  338. End Sub
  339. ' Create the morph frames.
  340. Private Sub cmdMorph_Click()
  341. Dim num_frames As Integer
  342. Dim frame As Integer
  343. Dim base_name As String
  344. Dim Dx As Single
  345. Dim Dy As Single
  346. Dim start_time As Single
  347. Dim stop_time As Single
  348. Dim minutes As Integer
  349.     ' Do nothing if the pictures are not loaded.
  350.     If (picOriginal(0).Picture = 0) Or _
  351.        (picOriginal(1).Picture = 0) _
  352.     Then
  353.         MsgBox "You must load pictures before morphing."
  354.         Exit Sub
  355.     End If
  356.     On Error Resume Next
  357.     num_frames = CInt(txtFrames.Text)
  358.     If Err.Number <> 0 Then num_frames = 10
  359.     On Error GoTo 0
  360.     base_name = txtBaseName.Text
  361.     ' Prepare for the transformation.
  362.     Screen.MousePointer = vbHourglass
  363.     picResult.Line (0, 0)-(picResult.ScaleWidth, picResult.ScaleHeight), _
  364.         picResult.BackColor, BF
  365.     DoEvents
  366.     start_time = Timer
  367.     Morphing = True
  368.     ' Restore the original images.
  369.     picOriginal(0).Cls
  370.     picOriginal(1).Cls
  371.     ' Save frame 0.
  372.     SavePicture picOriginal(0).Picture, base_name & "0.bmp"
  373.     picResult.Picture = picOriginal(0).Image
  374.     ' Make the frames.
  375.     For frame = 1 To num_frames
  376.         txtFrames.Text = Format$(frame)
  377.         DoEvents
  378.         ' Create the frame.
  379.         picResult.Line (0, 0)-(picResult.ScaleWidth, picResult.ScaleHeight), _
  380.             picResult.BackColor, BF
  381.         MorphImage frame / (num_frames + 1)
  382.         picResult.Picture = picResult.Image
  383.         ' Save the result.
  384.         SavePicture picResult.Picture, base_name & Format$(frame) & ".bmp"
  385.     Next frame
  386.     ' Save the last frame.
  387.     SavePicture picOriginal(1).Picture, base_name & Format$(num_frames) & ".bmp"
  388.     picResult.Picture = picOriginal(1).Image
  389.     txtFrames.Text = Format$(num_frames + 1)
  390.     ' Redraw the grids.
  391.     DrawGrid 0
  392.     DrawGrid 1
  393.     stop_time = Timer
  394.     minutes = (stop_time - start_time) \ 60
  395.     MsgBox "Ellapsed time: " & _
  396.         Format$(minutes) & ":" & _
  397.         Format$((stop_time - start_time) - minutes * 60, "00")
  398.     Screen.MousePointer = vbDefault
  399.     Morphing = False
  400. End Sub
  401. ' Draw the positioning grid.
  402. Private Sub DrawGrid(ByVal Index As Integer)
  403. Dim r As Integer
  404. Dim c As Integer
  405.     picOriginal(Index).Cls
  406.     ' Draw the lines.
  407.     For r = 0 To NUM_POINTS
  408.         For c = 0 To NUM_POINTS
  409.             If r > 0 Then
  410.                 picOriginal(Index).Line _
  411.                     (PointX(Index, r, c), PointY(Index, r, c))- _
  412.                     (PointX(Index, r, c + 1), PointY(Index, r, c + 1))
  413.             End If
  414.             If c > 0 Then
  415.                 picOriginal(Index).Line _
  416.                     (PointX(Index, r, c), PointY(Index, r, c))- _
  417.                     (PointX(Index, r + 1, c), PointY(Index, r + 1, c))
  418.             End If
  419.         Next c
  420.     Next r
  421.     ' Draw the control points.
  422.     For r = 0 To NUM_POINTS + 1
  423.         For c = 0 To NUM_POINTS + 1
  424.             picOriginal(Index).Line _
  425.                 (PointX(Index, r, c) - 1, PointY(Index, r, c) - 1)- _
  426.                 Step(3, 3), , BF
  427.         Next c
  428.     Next r
  429. End Sub
  430. ' Find the control point at this mouse position.
  431. Private Sub FindControlPoint(ByVal Index As Integer, ByVal X As Single, ByVal Y As Single, ByRef r As Integer, ByRef c As Integer)
  432. Dim Dx As Single
  433. Dim Dy As Single
  434.     For r = 0 To NUM_POINTS + 1
  435.         For c = 0 To NUM_POINTS + 1
  436.             Dx = Abs(PointX(Index, r, c) - X)
  437.             Dy = Abs(PointY(Index, r, c) - Y)
  438.             If (Dx < 2) And (Dy < 2) Then Exit Sub
  439.         Next c
  440.     Next r
  441.     ' The mouse is not over a control point.
  442.     r = -1
  443.     c = -1
  444. End Sub
  445. ' Initialize the positioning grid for this picture.
  446. Private Sub InitializeGrid(ByVal Index As Integer)
  447. Dim X As Single
  448. Dim Y As Single
  449. Dim r As Integer
  450. Dim c As Integer
  451.     GridDx = picOriginal(Index).ScaleWidth / (NUM_POINTS + 1)
  452.     GridDy = picOriginal(Index).ScaleHeight / (NUM_POINTS + 1)
  453.     Y = 0
  454.     For r = 0 To NUM_POINTS + 1
  455.         X = 0
  456.         For c = 0 To NUM_POINTS + 1
  457.             PointX(Index, r, c) = X
  458.             PointY(Index, r, c) = Y
  459.             X = X + GridDx
  460.         Next c
  461.         Y = Y + GridDy
  462.     Next r
  463. End Sub
  464. ' Create one frame in the animation.
  465. Private Sub MorphImage(ByVal fraction As Single)
  466. Dim input_pixels0() As RGBTriplet
  467. Dim input_pixels1() As RGBTriplet
  468. Dim result_pixels() As RGBTriplet
  469. Dim bits_per_pixel As Integer
  470. Dim row As Integer
  471. Dim col As Integer
  472. Dim ix_max As Single
  473. Dim iy_max As Single
  474. Dim x_in As Single
  475. Dim y_in As Single
  476. Dim ix_out As Long
  477. Dim iy_out As Long
  478. Dim ix_in As Long
  479. Dim iy_in As Long
  480. Dim Dx As Single
  481. Dim Dy As Single
  482. Dim dx1 As Single
  483. Dim dx2 As Single
  484. Dim dy1 As Single
  485. Dim dy2 As Single
  486. Dim v11 As Integer
  487. Dim v12 As Integer
  488. Dim v21 As Integer
  489. Dim v22 As Integer
  490. Dim r0 As Integer
  491. Dim g0 As Integer
  492. Dim b0 As Integer
  493. Dim r1 As Integer
  494. Dim g1 As Integer
  495. Dim b1 As Integer
  496. Dim s As Single
  497. Dim t As Single
  498. Dim found_grid As Boolean
  499.     ' Get the input pixels.
  500.     GetBitmapPixels picOriginal(0), input_pixels0, bits_per_pixel
  501.     GetBitmapPixels picOriginal(1), input_pixels1, bits_per_pixel
  502.     ' Get the pixels from pic_to.
  503.     GetBitmapPixels picResult, result_pixels, bits_per_pixel
  504.     ' Get the original image's bounds.
  505.     ix_max = picOriginal(0).ScaleWidth - 2
  506.     iy_max = picOriginal(0).ScaleHeight - 2
  507.     ' See where the grid points should be this fraction
  508.     ' of the way between the start and end grids.
  509.     For row = 0 To NUM_POINTS + 1
  510.         For col = 0 To NUM_POINTS + 1
  511.             MorphGridX(row, col) = PointX(0, row, col) * (1# - fraction) + PointX(1, row, col) * fraction
  512.             MorphGridY(row, col) = PointY(0, row, col) * (1# - fraction) + PointY(1, row, col) * fraction
  513.         Next col
  514.     Next row
  515.     ' Calculate the output pixel values.
  516.     For iy_out = 0 To picOriginal(0).ScaleHeight - 1
  517.         For ix_out = 0 To picOriginal(0).ScaleWidth - 1
  518.             ' Find the row and column in the current
  519.             ' grid that contains this point.
  520.             found_grid = False
  521.             For row = 0 To NUM_POINTS
  522.                 For col = 0 To NUM_POINTS
  523.                     If PointsToST(ix_out, iy_out, s, t, _
  524.                         MorphGridX(row, col), MorphGridY(row, col), _
  525.                         MorphGridX(row, col + 1), MorphGridY(row, col + 1), _
  526.                         MorphGridX(row + 1, col), MorphGridY(row + 1, col), _
  527.                         MorphGridX(row + 1, col + 1), MorphGridY(row + 1, col + 1)) _
  528.                     Then
  529.                         ' The point is in this grid.
  530.                         found_grid = True
  531.                         Exit For
  532.                     End If
  533.                 Next col
  534.                 If found_grid Then Exit For
  535.             Next row
  536.             If found_grid Then
  537.                 ' picOriginal(0)
  538.                 ' Find the corresponding points
  539.                 ' in picOriginal(i).
  540.                 STToPoints x_in, y_in, s, t, _
  541.                     PointX(0, row, col), PointY(0, row, col), _
  542.                     PointX(0, row, col + 1), PointY(0, row, col + 1), _
  543.                     PointX(0, row + 1, col), PointY(0, row + 1, col), _
  544.                     PointX(0, row + 1, col + 1), PointY(0, row + 1, col + 1)
  545.                 ' Interpolate to find the pixel's value.
  546.                 ' Find the nearest integral position.
  547.                 ix_in = Int(x_in)
  548.                 iy_in = Int(y_in)
  549.                 ' See if this is out of bounds.
  550.                 If (ix_in < 0) Or (ix_in > ix_max) Or _
  551.                    (iy_in < 0) Or (iy_in > iy_max) _
  552.                 Then
  553.                     ' The point is outside the image.
  554.                     ' Use black.
  555.                     r0 = 0
  556.                     g0 = 0
  557.                     b0 = 0
  558.                 Else
  559.                     ' The point lies within the image.
  560.                     ' Calculate its value.
  561.                     dx1 = x_in - ix_in
  562.                     dy1 = y_in - iy_in
  563.                     dx2 = 1# - dx1
  564.                     dy2 = 1# - dy1
  565.                     ' Calculate the red value.
  566.                     v11 = input_pixels0(ix_in, iy_in).rgbRed
  567.                     v12 = input_pixels0(ix_in, iy_in + 1).rgbRed
  568.                     v21 = input_pixels0(ix_in + 1, iy_in).rgbRed
  569.                     v22 = input_pixels0(ix_in + 1, iy_in + 1).rgbRed
  570.                     r0 = _
  571.                         v11 * dx2 * dy2 + v12 * dx2 * dy1 + _
  572.                         v21 * dx1 * dy2 + v22 * dx1 * dy1
  573.                     ' Calculate the green value.
  574.                     v11 = input_pixels0(ix_in, iy_in).rgbGreen
  575.                     v12 = input_pixels0(ix_in, iy_in + 1).rgbGreen
  576.                     v21 = input_pixels0(ix_in + 1, iy_in).rgbGreen
  577.                     v22 = input_pixels0(ix_in + 1, iy_in + 1).rgbGreen
  578.                     g0 = _
  579.                         v11 * dx2 * dy2 + v12 * dx2 * dy1 + _
  580.                         v21 * dx1 * dy2 + v22 * dx1 * dy1
  581.                     ' Calculate the blue value.
  582.                     v11 = input_pixels0(ix_in, iy_in).rgbBlue
  583.                     v12 = input_pixels0(ix_in, iy_in + 1).rgbBlue
  584.                     v21 = input_pixels0(ix_in + 1, iy_in).rgbBlue
  585.                     v22 = input_pixels0(ix_in + 1, iy_in + 1).rgbBlue
  586.                     b0 = _
  587.                         v11 * dx2 * dy2 + v12 * dx2 * dy1 + _
  588.                         v21 * dx1 * dy2 + v22 * dx1 * dy1
  589.                 End If
  590.                 ' picOriginal(1)
  591.                 ' Find the corresponding points
  592.                 ' in picOriginal(i).
  593.                 STToPoints x_in, y_in, s, t, _
  594.                     PointX(1, row, col), PointY(1, row, col), _
  595.                     PointX(1, row, col + 1), PointY(1, row, col + 1), _
  596.                     PointX(1, row + 1, col), PointY(1, row + 1, col), _
  597.                     PointX(1, row + 1, col + 1), PointY(1, row + 1, col + 1)
  598.                 ' Interpolate to find the pixel's value.
  599.                 ' Find the nearest integral position.
  600.                 ix_in = Int(x_in)
  601.                 iy_in = Int(y_in)
  602.                 ' See if this is out of bounds.
  603.                 If (ix_in < 0) Or (ix_in > ix_max) Or _
  604.                    (iy_in < 0) Or (iy_in > iy_max) _
  605.                 Then
  606.                     ' The point is outside the image.
  607.                     ' Use black.
  608.                     r1 = 0
  609.                     g1 = 0
  610.                     b1 = 0
  611.                 Else
  612.                     ' The point lies within the image.
  613.                     ' Calculate its value.
  614.                     dx1 = x_in - ix_in
  615.                     dy1 = y_in - iy_in
  616.                     dx2 = 1# - dx1
  617.                     dy2 = 1# - dy1
  618.                     ' Calculate the red value.
  619.                     v11 = input_pixels1(ix_in, iy_in).rgbRed
  620.                     v12 = input_pixels1(ix_in, iy_in + 1).rgbRed
  621.                     v21 = input_pixels1(ix_in + 1, iy_in).rgbRed
  622.                     v22 = input_pixels1(ix_in + 1, iy_in + 1).rgbRed
  623.                     r1 = _
  624.                         v11 * dx2 * dy2 + v12 * dx2 * dy1 + _
  625.                         v21 * dx1 * dy2 + v22 * dx1 * dy1
  626.                     ' Calculate the green value.
  627.                     v11 = input_pixels1(ix_in, iy_in).rgbGreen
  628.                     v12 = input_pixels1(ix_in, iy_in + 1).rgbGreen
  629.                     v21 = input_pixels1(ix_in + 1, iy_in).rgbGreen
  630.                     v22 = input_pixels1(ix_in + 1, iy_in + 1).rgbGreen
  631.                     g1 = _
  632.                         v11 * dx2 * dy2 + v12 * dx2 * dy1 + _
  633.                         v21 * dx1 * dy2 + v22 * dx1 * dy1
  634.                     ' Calculate the blue value.
  635.                     v11 = input_pixels1(ix_in, iy_in).rgbBlue
  636.                     v12 = input_pixels1(ix_in, iy_in + 1).rgbBlue
  637.                     v21 = input_pixels1(ix_in + 1, iy_in).rgbBlue
  638.                     v22 = input_pixels1(ix_in + 1, iy_in + 1).rgbBlue
  639.                     b1 = _
  640.                         v11 * dx2 * dy2 + v12 * dx2 * dy1 + _
  641.                         v21 * dx1 * dy2 + v22 * dx1 * dy1
  642.                 End If
  643.                 ' Combine the values of the two colors.
  644.                 With result_pixels(ix_out, iy_out)
  645.                     .rgbRed = r0 * (1# - fraction) + r1 * fraction
  646.                     .rgbGreen = g0 * (1# - fraction) + g1 * fraction
  647.                     .rgbBlue = b0 * (1# - fraction) + b1 * fraction
  648.                 End With
  649.             Else
  650.                 With result_pixels(ix_out, iy_out)
  651.                     .rgbRed = 255
  652.                     .rgbGreen = 0
  653.                     .rgbBlue = 0
  654.                 End With
  655.             End If ' End if found_grid ...
  656.         Next ix_out
  657.     Next iy_out
  658.     ' Set pic_to's pixels.
  659.     SetBitmapPixels picResult, bits_per_pixel, result_pixels
  660.     picResult.Picture = picResult.Image
  661. End Sub
  662. ' Start in the current directory.
  663. Private Sub Form_Load()
  664. Dim i As Integer
  665. Dim file_name As String
  666.     For i = 0 To 1
  667.         picOriginal(i).AutoSize = True
  668.         picOriginal(i).ScaleMode = vbPixels
  669.         picOriginal(i).AutoRedraw = True
  670.         picOriginal(i).ForeColor = vbWhite
  671.     Next i
  672.     picResult.ScaleMode = vbPixels
  673.     picResult.AutoRedraw = True
  674.     dlgOpenFile.CancelError = True
  675.     dlgOpenFile.InitDir = App.Path
  676.     file_name = App.Path
  677.     If Right$(file_name, 1) <> "\" Then file_name = file_name & "\"
  678.     file_name = file_name & "morph_"
  679.     txtBaseName.Text = file_name
  680.     ArrangeControls
  681. End Sub
  682. Private Sub mnuFileLoadCoordinates_Click()
  683. Dim file_name As String
  684. Dim fnum As Integer
  685. Dim i As Integer
  686. Dim r As Integer
  687. Dim c As Integer
  688.     ' Let the user select a file.
  689.     SetFiltersText
  690.     On Error Resume Next
  691.     dlgOpenFile.Flags = cdlOFNFileMustExist + cdlOFNHideReadOnly
  692.     dlgOpenFile.ShowOpen
  693.     If Err.Number = cdlCancel Then
  694.         Exit Sub
  695.     ElseIf Err.Number <> 0 Then
  696.         Beep
  697.         MsgBox "Error selecting file.", , vbExclamation
  698.         Exit Sub
  699.     End If
  700.     On Error GoTo 0
  701.     Screen.MousePointer = vbHourglass
  702.     DoEvents
  703.     file_name = Trim$(dlgOpenFile.FileName)
  704.     dlgOpenFile.InitDir = Left$(file_name, Len(file_name) _
  705.         - Len(dlgOpenFile.FileTitle) - 1)
  706.     ' Load the data.
  707.     fnum = FreeFile
  708.     Open file_name For Input As fnum
  709.     For i = 0 To 1
  710.         For r = 0 To NUM_POINTS + 1
  711.             For c = 0 To NUM_POINTS + 1
  712.                 Input #fnum, PointX(i, r, c), PointY(i, r, c)
  713.             Next c
  714.         Next r
  715.     Next i
  716.     Close fnum
  717.     ' Redraw the positioning grid.
  718.     For i = 0 To 1
  719.         DrawGrid i
  720.     Next i
  721.     Screen.MousePointer = vbDefault
  722. End Sub
  723. ' Load the indicated file.
  724. Private Sub mnuFileOpen_Click(Index As Integer)
  725. Dim file_name As String
  726.     ' Let the user select a file.
  727.     SetFiltersGraphic
  728.     On Error Resume Next
  729.     dlgOpenFile.Flags = cdlOFNFileMustExist + cdlOFNHideReadOnly
  730.     dlgOpenFile.ShowOpen
  731.     If Err.Number = cdlCancel Then
  732.         Exit Sub
  733.     ElseIf Err.Number <> 0 Then
  734.         Beep
  735.         MsgBox "Error selecting file.", , vbExclamation
  736.         Exit Sub
  737.     End If
  738.     On Error GoTo 0
  739.     Screen.MousePointer = vbHourglass
  740.     DoEvents
  741.     file_name = Trim$(dlgOpenFile.FileName)
  742.     dlgOpenFile.InitDir = Left$(file_name, Len(file_name) _
  743.         - Len(dlgOpenFile.FileTitle) - 1)
  744.     FileTitle(Index) = dlgOpenFile.FileTitle
  745.     Caption = "Morph [" & FileTitle(0) & " -> " & FileTitle(1) & "]"
  746.     ' Open the original file.
  747.     On Error GoTo LoadError
  748.     picOriginal(Index).Picture = LoadPicture(file_name)
  749.     On Error GoTo 0
  750.     picOriginal(Index).Picture = picOriginal(Index).Image
  751.     ' Draw the positioning grid.
  752.     InitializeGrid Index
  753.     DrawGrid Index
  754.     ' Arrange the controls.
  755.     If Index = 0 Then
  756.         picOriginal(1).Width = picOriginal(0).Width
  757.         picOriginal(1).Height = picOriginal(0).Height
  758.     Else
  759.         picOriginal(0).Width = picOriginal(1).Width
  760.         picOriginal(0).Height = picOriginal(1).Height
  761.     End If
  762.     ArrangeControls
  763.     Screen.MousePointer = vbDefault
  764.     Exit Sub
  765. LoadError:
  766.     Screen.MousePointer = vbDefault
  767.     MsgBox "Error " & Format$(Err.Number) & _
  768.         " opening file '" & file_name & "'" & vbCrLf & _
  769.         Err.Description
  770. End Sub
  771. Private Sub mnuFileSaveCoordinates_Click()
  772. Dim file_name As String
  773. Dim fnum As Integer
  774. Dim i As Integer
  775. Dim r As Integer
  776. Dim c As Integer
  777.     ' Let the user select a file.
  778.     SetFiltersText
  779.     On Error Resume Next
  780.     dlgOpenFile.Flags = cdlOFNOverwritePrompt + cdlOFNHideReadOnly
  781.     dlgOpenFile.ShowSave
  782.     If Err.Number = cdlCancel Then
  783.         Exit Sub
  784.     ElseIf Err.Number <> 0 Then
  785.         Beep
  786.         MsgBox "Error selecting file.", , vbExclamation
  787.         Exit Sub
  788.     End If
  789.     On Error GoTo 0
  790.     Screen.MousePointer = vbHourglass
  791.     DoEvents
  792.     file_name = Trim$(dlgOpenFile.FileName)
  793.     dlgOpenFile.InitDir = Left$(file_name, Len(file_name) _
  794.         - Len(dlgOpenFile.FileTitle) - 1)
  795.     ' Save the grid data into the file.
  796.     fnum = FreeFile
  797.     Open file_name For Output As fnum
  798.     For i = 0 To 1
  799.         For r = 0 To NUM_POINTS + 1
  800.             For c = 0 To NUM_POINTS + 1
  801.                 Write #fnum, PointX(i, r, c), PointY(i, r, c)
  802.             Next c
  803.         Next r
  804.     Next i
  805.     Close fnum
  806.     Screen.MousePointer = vbDefault
  807. End Sub
  808. ' Copy the control points from the right
  809. ' picture to the left.
  810. Private Sub mnuGridCopyLeftToRight_Click()
  811.     CopyPoints 1, 0
  812. End Sub
  813. ' Copy the control points from the left
  814. ' picture to the right.
  815. Private Sub mnuGridCopyRightToLeft_Click()
  816.     CopyPoints 0, 1
  817. End Sub
  818. ' Reset the grid.
  819. Private Sub mnuGridResetGrid_Click(Index As Integer)
  820.     InitializeGrid Index
  821.     DrawGrid Index
  822. End Sub
  823. ' Swap the left and right grids.
  824. Private Sub mnuGridSwap_Click()
  825. Dim row As Integer
  826. Dim col As Integer
  827. Dim tmp As Single
  828.     For row = 0 To NUM_POINTS + 1
  829.         For col = 0 To NUM_POINTS + 1
  830.             tmp = PointX(0, row, col)
  831.             PointX(0, row, col) = PointX(1, row, col)
  832.             PointX(1, row, col) = tmp
  833.             tmp = PointY(0, row, col)
  834.             PointY(0, row, col) = PointY(1, row, col)
  835.             PointY(1, row, col) = tmp
  836.         Next col
  837.     Next row
  838.     DrawGrid 0
  839.     DrawGrid 1
  840. End Sub
  841. ' Make the left grid symmetric by copying its left
  842. ' half to its right half.
  843. Private Sub mnuGridSymLeftLeftToRight_Click()
  844.     MakeLeftToRightSymmetric 0
  845. End Sub
  846. ' Make the left grid symmetric by copying its right
  847. ' half to its left half.
  848. Private Sub mnuGridSymLeftRightToLeft_Click()
  849.     MakeRightToLeftSymmetric 0
  850. End Sub
  851. ' Make the right grid symmetric by copying its left
  852. ' half to its right half.
  853. Private Sub mnuGridSymRightLeftToRight_Click()
  854.     MakeLeftToRightSymmetric 1
  855. End Sub
  856. ' Make the right grid symmetric by copying its right
  857. ' half to its left half.
  858. Private Sub mnuGridSymRightRightToLeft_Click()
  859.     MakeRightToLeftSymmetric 1
  860. End Sub
  861. ' Start dragging a control point.
  862. Private Sub picOriginal_MouseDown(Index As Integer, Button As Integer, Shift As Integer, X As Single, Y As Single)
  863.     If Morphing Then Exit Sub
  864.     ' See if the mouse is over a control point.
  865.     FindControlPoint Index, X, Y, DragR, DragC
  866. End Sub
  867. ' Move a control point.
  868. Private Sub picOriginal_MouseMove(Index As Integer, Button As Integer, Shift As Integer, X As Single, Y As Single)
  869. Dim row As Integer
  870. Dim col As Integer
  871.     If Morphing Then Exit Sub
  872.     ' Do nothing if we are not dragging.
  873.     If DragR < 0 Then
  874.         ' No drag is in progress.
  875.         ' See if the mouse is over a control point.
  876.         FindControlPoint Index, X, Y, row, col
  877.         If row >= 0 Then
  878.             ' We're over a control point. Display
  879.             ' the crosshair cursor.
  880.             If picOriginal(Index).MousePointer <> vbCrosshair Then
  881.                 picOriginal(Index).MousePointer = vbCrosshair
  882.             End If
  883.         Else
  884.             ' We're not over a control point. Display
  885.             ' the default cursor.
  886.             If picOriginal(Index).MousePointer <> vbDefault Then
  887.                 picOriginal(Index).MousePointer = vbDefault
  888.             End If
  889.         End If
  890.     Else
  891.         ' A drag is in progress.
  892.         ' Make sure the point stays in bounds.
  893.         If X < 1 Then X = 1
  894.         If X > picOriginal(Index).ScaleWidth Then X = picOriginal(Index).ScaleWidth
  895.         If Y < 1 Then Y = 1
  896.         If Y > picOriginal(Index).ScaleHeight Then Y = picOriginal(Index).ScaleHeight
  897.         ' Make sure edge points stay on the edge.
  898.         If DragC = 0 Then X = 0
  899.         If DragC = NUM_POINTS + 1 Then X = picOriginal(Index).ScaleWidth
  900.         If DragR = 0 Then Y = 0
  901.         If DragR = NUM_POINTS + 1 Then Y = picOriginal(Index).ScaleHeight
  902.         ' Move the control point.
  903.         PointX(Index, DragR, DragC) = X
  904.         PointY(Index, DragR, DragC) = Y
  905.         ' Redraw the control grid.
  906.         DrawGrid Index
  907.     End If
  908. End Sub
  909. ' Finish moving a control point.
  910. Private Sub picOriginal_MouseUp(Index As Integer, Button As Integer, Shift As Integer, X As Single, Y As Single)
  911.     DragR = -1
  912. End Sub
  913.