Contents
Articles
Behaviors
Books
Director News
Director Web Sites
FAQ
Games
Mailing Lists
News Groups
Project Examples
Reviews
Software
Tools
Useful Web Sites
Utilities
Xtras

Don't miss these
cXtraChangeRes
Roil Button-Alphamania
CD Autorun
Viking board game
Director 8 and Lingo: Inside Macromedia Series
Prevent Hour Glass Cursor after AVI Ends
cXtraCalendar
Import text as cast members
Maeda @ Media
Hangman
 

 

 

Behavior Dave's 3D engine V7.1

Added on 1/31/2000

 

Compatibilities:
D7 D8 Mac PC Script Shockwave

This item has not yet been rated

Author: DaveCole

Create 3d Effects using director polygons The newest version and full example files are always available at http://www.dave-cole.com/3D/

-- Dave's Lingo 3D Engine v7.1 FULL - Last Modified 12/14/99
-- Dave Cole - dcole@sigma6.com
-- Special thanks to Terry Schussler of Trevi Media (http://www.trevimedia.com) for optimizations!
--
-- Dave's 3D Engine is Shareware.  If you use this source for commercial gain, you
-- must send a $20 shareware registration fee to:
--
-- Dave Cole
-- 575 Leroy
-- Ferndale, MI 48220
--
--
--
-- Copyright (c) 1998 David Cole
-- All rights reserved.
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by David Cole, as well as that the user, if using this software
-- for financial gain, has paid the $20 shareware registration fee.
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
--
-- You may freely redistribute this 3D engine so long as the credits and accompanying
-- credits README file remain with the engine at all times.  If you modify it, please
-- annotate notes about your modification and notify me about your changes -- I would
-- like to learn what others can do with this thing!
--
-- The intention of this code is to allow the representation, transformation, and 2D
-- projection and display of 3-dimensional graphics from within a director film.  The
-- interface has been styled loosely after OpenGL for ease of use.
--
-- If this source exists in its original distribution, a manual is available in cast
-- member 3.
--
-- This graphics engine uses a right-handed coordinate system with a view that defaults
-- to looking down the negative z axis from the origin.
--
-- This is the FULL release of Dave's Lingo 3D Engine.  That means that although care
-- has been taken to optimize the routines for speed, the primary intention of this code is
-- to offer a flexibile, accurate, fully-functional 3D graphics system.
--
-- All points use homogenous coordinates.  4x4 Matrices are represented as nested lists:
-- (i.e. [[],[],[],[]]).  1x4 Matrices are represented as a single 4-element list (i.e.
-- [0.0, 0.0, 0.0, 1.0]).  
--
-- *Note: If this engine is removed from its original distribution movie, the lingo below
-- in green can be deleted, all green lingo below is demo-movie specific and not necessary
-- for the 3D Engine to function properly.




--------------------------------------------------------------------------------------------------------
-- Globals  --------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------

global mModelView         -- A 4x4 matrix that represents the current ModelView matrix.
global mProjection        -- A 4x4 matrix that represents the current Projection matrix.
global mModelViewStack    -- A stack of saved ModelView matrices
global mProjectionStack   -- A stack of saved Projection matrices
global mv                 -- 1: Current Matrix Operations performed on ModelView matrix, 0: Current Matrix Ops Performed on Projection Matrix
global point              -- A point datatype for misc. use (in homogenous coordinates)
global xCoefficient       -- used in viewport transformations
global yCoefficient       -- used in viewport transformations
global halffov            -- used to scale sprites accurately
global sortSprites        -- 1: Sprites with a nearer Z value will take a higher # sprite channel (slower)
--                        -- 0: Sprites will stay in their channels (less accurate looking but faster)
global cullBackfaces      -- 1: Cull backfacing quads, 0: don't
global cullBackfaces_cw   -- 1: Clockwise defined vertices determine the front face of a quad, 0: Counterclockwise
--                        -- .. This property only is checked if cullBackfaces = 1
global activateClipping   -- 1: Quads/Sprites are clipped when outside the frustum, 0: no clipping is done
global lookupList
global DWatcher
global DWatcher_newChange
global use3DWatcher

global lightingList       -- a list of lights (format: [uniqueID:[x, y, z, r, g, b]])

global debug              -- Set to 1 to dump tons of debugging information.


global xSlider, ySlider, zSlider, xScale, yScale, zScale, Frustum, rox, roy, roz, roton  -- custom demo program specific


on prepareMovie
  clearGlobals
  
  set mModelView = [[1000, 0, 0, 0], [0, 1000, 0, 0], [0, 0, 1000, 0], [0, 0, 0, 1000]]
  set mProjection = [[1000, 0, 0, 0], [0, 1000, 0, 0], [0, 0, 1000, 0], [0, 0, 0, 1000]]
  
  set activateClipping = 0
  set use3DWatcher = 0
  set cullBackfaces = 1
  set cullBackfaces_cw = 1
  set DWatcher_newChange = 1
  set mModelViewStack = []
  set mProjectionStack = []
  set point = [0, 0, 0, 1.0]
  set lookupList = [:]
  sort lookupList
  set mv = 1
  set sortSprites = 1
  set halffov = 1
  
  set debug = 0                 -- Set to 1 to print tons of debugging info
  ---- custom for-the-demo-only, you can delete this stuff
  set Frustum = 0.8
  set xSlider = 0.0
  set ySlider = 0.0
  set zSlider = -40.0
  
  set xScale = 1.0
  set yScale = 1.0
  set zScale = 1.0
  
  set rox = 0.0
  set roy = 0.0
  set roz = 0.0
  set roton = 1
  ---- end custom for-the-demo-only
  
end

on stopMovie
  set the actorlist = []
end

----------------------------------------------------------------------------------------------------------
--  HIGH-LEVEL ROUTINES  ---------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------

-- xFormPoint takes a 4-element list which defines a point as [x, y, z, w] (homogeneous coordinates) and
-- transforms it into a screen position point in the form of a 3-element list [h, v, z] which represents
-- where on the screen the point should appear after being transformed by the ModelView matrix, the
-- projection matrix, the perspective division, and the viewport transformation.  These are known as the
-- window coordinates.  The z element is returned so that the programmer can illicit depth information
-- about this point.  For more info on this process, research a 3D graphics tutorial near you.
-- 0 is returned if the point is not to be drawn. (i.e. it is outside of the clipping planes.)
on xFormPoint p
  --  if debug then put "xFormPoint--------------"
  --  if debug then put "ModelView: "&RETURN&mModelView
  --  if debug then put "Projection:"&RETURN&mProjection
  --  if debug then put "p = "&p
  set z = getAProp(lookupList, p)
  if z = 0 then
    set m = Matrix1x4Mult(p, mModelView)                    -- Do ModelView xformation
    if debug then put "XFormMV:"&RETURN&m
    if (m <> 0) then set m = Matrix1x4Mult(m, mProjection)  -- Do Projection xformation
    else
      beep
      put "ERROR!:  Point couldn't be converted: "&p
      return 0
    end if
    if debug then put "XFormP:"&RETURN&m
    set m = PerspectiveDivide(m)                            -- Do Perspective division & clipping
    if debug then put "XFormPD:"&RETURN&m
    if (m <> 0) then set m = ViewPortXForm(m)               -- Do viewport transformation
    if debug then put "XFormV:"&RETURN&m
    
    addProp(lookUplist, p, m)
    return m
  else
    return z
  end if
  
end

-- Nudge can be used by a 3DSprite or 3DQuad, or your own custom code, to retrieve the transformed
-- coordinates of a geometry based on the current ModelView matrix without performing any of the
-- projection transformation, perspective division, clipping, or viewport transformations.
-- Useful in multi-step transformations.
on Nudge p
  return(Matrix1x4Mult(p, mModelView))
end

-- pFrustum creates a perspective projection matrix with the viewing frustum volume
-- described by the arguments and multiplies it to the current projection matrix.  It is recommended
-- you call mLoadIdentity before calling this, since its effects are cumulative.  (left, bottom, -near) and
-- (right, top, -near) specify the (x, y, z) coordinates of the lower-left and upper-right corners of the
-- near clipping plane; near and far give the distances from the viewpoint to the near and far clipping planes.
-- near & far should be positive.
on pFrustum left, right, bottom, top, near, far
  lookupList = [:]
  set nn = 2.0*near
  set rl = right - left
  set tb = top - bottom
  set fn = far - near
  set mProjection = [[integer(1000*nn/rl), 0, integer(1000*(right+left)/rl), 0], [0, integer(1000*nn/tb), integer(1000*(top+bottom)/tb), 0], [0, 0, integer(1000*-(far+near)/fn), integer(1000*-(far*nn)/fn)], [0, 0, -1000, 0]]
  set halffov = (1.5708 / abs(atan(float(top) / float(near))))
  return 1  
end

-- pOrtho creates an orthagonal projection matrix with the parallel viewing volume described by the given
-- arguments and multiplies it to the current projection matrix.  It is recommended you call mLoadIdentity before
-- calling this, since its effects are cumulative.  (left, bottom, -near) and (right, top, -near) are mapped to
-- the lower-left and upper-right corners of the viewport window in the near clipping plane.  (left, bottom, -far)
-- and (right, top, -far) are mapped to the lower-left and upper-right corners of the far clipping plane which
-- are also mapped to the same corners of the viewport window.  Both near and far can be positive or negative.
on pOrtho left, right, bottom, top, near, far
  lookUpList = [:]
  set rl = right - left
  set tb = top - bottom
  set fn = far - near
  set mProjection = [[integer(2000/rl), 0, 0, integer(1000*(right+left)/rl)], [0, integer(2000/tb), 0, integer(1000*(top+bottom)/tb)], [0, 0, integer(-200/fn), integer(1000*(far+near)/fn)], [0, 0, 0, 1000]]
  set halffov = -1
  return 1
end



-- pViewPort defines the viewport for the view onto the 3D world.  It defines a pixel rectangle in the
-- window where the final image is mapped.  x and y specify the upper lefthand corner of the viewport,
-- width and height are the size of the viewport rectangle in pixels.  An example use of this would
-- be calling pViewPort(0, 0, windowWidth, windowHeight).
on pViewPort x, y, width, height
  set xCoefficient = (width/2) + x
  set yCoefficient = (height/2) + y
  return 1
end

----------------------------------------------------------------------------------------------------------
--  MATRIX OPERATIONS  -----------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------
-- mSelectMatrix takes either "Projection" or "ModelView" as arguments, and designates the current matrix
-- to have any of the transformations or matrix operations done to it.
on mSelectMatrix arg
  if (arg) = "Projection" then set mv = 0
  else set mv = 1
  return 1
end

-- Push current matrix onto stack, current matrix is a copy of what is on top of the stack until you change it.
on mPush
  if (mv) then
    addAt(mModelViewStack, 1, mModelView)
  else
    addAt(mProjectionStack, 1, mProjection)
  end if
  return 1
end

-- Pop a matrix off the stack, current matrix is now what was on top of the stack
on mPop
  lookUpList = [:]
  if (mv) then
    if count(mModelViewStack) then
      set mModelView = getAt(mModelViewStack, 1)
      deleteAt(mModelViewStack, 1)
    end if
  else
    if count(mProjectionStack) then
      set mProjection = getAt(mProjectionStack, 1)
      deleteAt(mProjectionStack, 1)
    end if
  end if
  return 1
end

-- Load the identity matrix into the current matrix
on mLoadIdentity
  lookupList = [:]
  if (mv) then
    set mModelView = [[1000, 0, 0, 0], [0, 1000, 0, 0], [0, 0, 1000, 0], [0, 0, 0, 1000]]
  else
    set mProjection = [[1000, 0, 0, 0], [0, 1000, 0, 0], [0, 0, 1000, 0], [0, 0, 0, 1000]]
  end if
  return 1
end
---------------------------------------------------------------------------------------------------
--   MODELVIEW TRANSFORMATIONS   ------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
-- MODELING TRANSFORMATIONS:

-- Translate the current matrix by x, y, z
-- Viewing transformations should always preceed modeling transformation in your code.
on xTranslate x, y, z
  lookUpList = [:]
  set m1 = [[1000, 0, 0, integer(1000*x)], [0, 1000, 0, integer(1000*y)], [0, 0, 1000, integer(1000*z)], [0, 0, 0, 1000]]
  set mModelView = Matrix4x4Mult(m1, mModelView)
  if mModelView <> 0 then return 1
  else return 0
end

-- Rotate the current matrix on the X axis by angle (in radians)
-- Viewing transformations should always preceed modeling transformation in your code.
on xRotateX a
  lookUpList = [:]
  set m3 = [[1000, 0, 0, 0], [0, integer(1000*cos(a)), integer(1000*-sin(a)), 0], [0, integer(1000*sin(a)), integer(1000*cos(a)), 0], [0, 0, 0, 1000]]
  set mModelView = Matrix4x4Mult(m3, mModelView)
  if mModelView <> 0 then return 1
  else return 0
end

-- Rotate the current matrix on the Y axis by angle (in radians)
-- Viewing transformations should always preceed modeling transformation in your code.
on xRotateY a
  lookUpList = [:]
  set m4 = [[integer(1000*cos(a)), 0, integer(1000*sin(a)), 0], [0, 1000, 0, 0], [integer(1000*-sin(a)), 0, integer(1000*cos(a)), 0], [0, 0, 0, 1000]]
  set mModelView = Matrix4x4Mult(m4, mModelView)
  if mModelView <> 0 then return 1
  else return 0
end

-- Rotate the current matrix on the Z axis by angle (in radians)
-- Viewing transformations should always preceed modeling transformation in your code.
on xRotateZ a
  lookUpList = [:]
  set m5 = [[integer(1000*cos(a)), integer(1000*-sin(a)), 0, 0], [integer(1000*sin(a)), integer(1000*cos(a)), 0, 0], [0, 0, 1000, 0], [0, 0, 0, 1000]]
  set mModelView = Matrix4x4Mult(m5, mModelView)
  if mModelView <> 0 then return 1
  else return 0
end

-- Scale the current matrix by x, y, z (>1.0 grows, <1.0 shrinks)
-- Viewing transformations should always preceed modeling transformation in your code.
on xScale x, y, z
  lookUpList = [:]
  set m2 = [[integer(1000*x), 0, 0, 0], [0, integer(1000*y), 0, 0], [0, 0, integer(1000*z), 0], [0, 0, 0, 1000]]
  set mModelView = Matrix4x4Mult(m2, mModelView)
  if mModelView <> 0 then return 1
  else return 0
end


-- VIEWING TRANSFORMATIONS: Camera placement routines:

-- pilotView uses the analogy of a plane to position the camera, with the runway at the origin and the
-- plane at coordinates (plane_x, plane_y, plane_z), with a roll, pitch, and heading (in all in degrees)
-- Viewing transformations should always preceed modeling transformation in your code.
on pilotView plane_x, plane_y, plane_z, roll, pitch, heading
  lookUpList = [:]
  set roll = (roll/360.0) * (2.0*PI)
  set pitch = (pitch/360.0) * (2.0*PI)
  set heading = (heading/360.0) * (2.0*PI)
  
  if (xRotateZ(roll) AND xRotateY(pitch) AND xRotateX(heading) AND xTranslate(-plane_x, -plane_y, -plane_z)) then
    return 1
  else
    return 0
  end if
end



-- polarView uses the analogy of a camera orbiting around an object that's centered at the origin, constantly
-- pointing at the origin.  Distance defines the radius of the orbit, azimuth describes the angle of rotation
-- of the camera around the object on the x-y plane, measured from the positive y-axis.  Elevation measures
-- the angle of rotation of the camera in the y-z plane, measured from the positive z-axis.  Twist represents
-- the rotation of the viewing volume around its line of sight.
-- Viewing transformations should always preceed modeling transformation in your code.
on polarView distance, twist, elevation, azimuth
  lookUpList = [:]
  if (xTranslate(0, 0, -distance) AND xRotateZ(-twist) AND xRotateX(-elevation) AND xRotateZ(azimuth)) then
    return 1
  else
    return 0
  end if
end

-----------------------------------------------------------------------------------------------------
-- Utility Routines ---------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------
on spawnDWatcher
  set DWatcher = new (script "3DWatcher")
end

on killDWatcher
  repeat while deleteOne(the actorlist, DWatcher)
  end repeat
end

-- isBackfacing determines if, from the given list of transformed vertices and certain environmental variables,
-- a quad's front or back is facing the camera, and returns a 1 if it is backfacing, 0 otherwise.
on isBackfacing vPList
  a = 0
  repeat with i = 0 to 3
    set z = ((i + 1) mod 4)
    set m = i+1
    set n = z+1
    a = a + ((vPList[m][1] * vPList[n][2]) - (vPList[n][1] * vPList[m][2]))
  end repeat
  set a = a/2.0
  if cullBackfaces_cw then
    if a > 0 then return 0
    else return 1
  else
    if a > 0 then return 1
    else return 0
  end if
end


-- zSort sets the locZ properties of the
on zSort listB
  
  put count(listB) into listBCount
  repeat with i = 1 to listBCount
    set vP = listB[i].myVPos
    
    
    if vP <> 0 then
      sprite(listb[i].mySprite).locZ = 1000-(vP[3] * 1000)    
    end if      
  end repeat
  
  return 0
  
end

-- Juggle is an old sprite sorting routine for D6.5 and below.  If you are using D7, use the zSort handler above.
-- It works just like Juggle but doesn't move any sprites around, it instead uses the locZ property and takes one
-- less argument.
on Juggle listB, lowSprite
  global passCtr
  global countlist
  set listA = [:]
  sort listA
  
  put count(listB) into listBCount
  repeat with i = 1 to listBCount
    set vP = the myVPos of getAt(listB, i)
    
    if vP <> 0 then
      
      addProp(listA, getAt(vP, 3), getAt(listB, i))
      
    else
      addProp(listA, 0.0, getAt(listB, i))
      
    end if      
  end repeat
  set countlist = count(lista)
  --sort listA
  --put listA
  set j = 0
  
  put (lowSprite + listBCount - 1) into highSprite
  repeat with i = highSprite down to lowSprite
    set j = j + 1
    set z= getAt(listA, j)
    --    fixScriptInstanceList(z, i)
    
    setSprite(z, i)
    
    set the member of sprite i = the myMember of z  
    set the rect of sprite i = the myRect of z
    set the blend of sprite i = the myBlend of z
    set the ink of sprite i = the myInk of z
    
    
    
    -- backColor, foreColor, editable, moveableSprite, constraint, trails
  end repeat
  
  return 0
  
end



------------------------------------------------------------------------------------------
-- OTHER UTILITY & MATH FUNCTIONS YOU PROBABLY DON'T NEED TO DIRECTLY ACCESS -------------
------------------------------------------------------------------------------------------


-- PerspectiveDivide converts a homogeneous coordinate into a normalized device coordinate.
-- point is a 4 element list.  Returns a 3-element list on success, 0 if the point is not to be drawn.
on PerspectiveDivide thePoint
  
  if count(thePoint) = 4 then
    set w = getAt(thePoint, 4)
    if w <> 0 then
      set x = getAt(thePoint, 1)
      set y = getAt(thePoint, 2)
      set z = getAt(thePoint, 3)
      
      if activateClipping = TRUE then
        case TRUE of
          (z < -w), (z > w), (y < -w), (y > w), (x < -w), (x > w)   : return 0   -- clipping
        end case
      end if
      
      return [x/w, y/w, abs(z/w)]
    else
      return 0
    end if
  else
    return 0
  end if    
end

-- ViewportXForm takes a normalized device coordinate point and transforms it into a
-- window coordinate.  The argument is a 3-element list.  A 3-element list, [h, v, z] is
-- returned on success.  0 if the point is not to be drawn
on ViewportXForm thePoint
  if count(thePoint) = 3 then
    return [(getAt(thePoint, 1) + 1.0) * xCoefficient, (getAt(thePoint, 2) + 1.0) * yCoefficient, getAt(thePoint, 3)]
  else
    return 0
  end if
end

--Useful math functions

-- 4x4 Matrices are defined as nested lists:  [[],[],[],[]]
-- 1x4 Matrices are defined as a 4 element list: [,,,]

on test
  a = [3,3,3,3]
  
  
  starttimer
  repeat with i = 1 to 500000
    set z = getAt(a, 3)
  end repeat
  put the timer
  
  starttimer
  repeat with i = 1 to 500000
    z = a[3]
  end repeat
  put the timer
  
end

--Matrix4x4Mult takes two 4x4 matrices, multiples them and returns the 4x4 result.
-- (Thanks to Jakob Hede Madsen for the optimization!)
on Matrix4x4Mult a, b
  
  a1 = a[1]
  if a1.count - b.count then
    put "Error: Could not multiply matrices, a.cols != b.rows != 4."
    return 0
  end if
  ----
  a2 = a[2]
  a3 = a[3]
  a4 = a[4]
  --
  b1 = b[1]
  b2 = b[2]
  b3 = b[3]
  b4 = b[4]
  --------
  a11 = a1[1]
  a12 = a1[2]
  a13 = a1[3]
  a14 = a1[4]
  --
  a21 = a2[1]
  a22 = a2[2]
  a23 = a2[3]
  a24 = a2[4]
  --
  a31 = a3[1]
  a32 = a3[2]
  a33 = a3[3]
  a34 = a3[4]
  --
  a41 = a4[1]
  a42 = a4[2]
  a43 = a4[3]
  a44 = a4[4]
  ----
  b11 = b1[1]
  b12 = b1[2]
  b13 = b1[3]
  b14 = b1[4]
  --
  b21 = b2[1]
  b22 = b2[2]
  b23 = b2[3]
  b24 = b2[4]
  --
  b31 = b3[1]
  b32 = b3[2]
  b33 = b3[3]
  b34 = b3[4]
  --
  b41 = b4[1]
  b42 = b4[2]
  b43 = b4[3]
  b44 = b4[4]
  ----
  return [¬
[((a11*b11)+(a12*b21)+(a13*b31)+(a14*b41))/1000,¬
((a11*b12)+(a12*b22)+(a13*b32)+(a14*b42))/1000,¬
((a11*b13)+(a12*b23)+(a13*b33)+(a14*b43))/1000,¬
((a11*b14)+(a12*b24)+(a13*b34)+(a14*b44))/1000],¬
[((a21*b11)+(a22*b21)+(a23*b31)+(a24*b41))/1000,¬
((a21*b12)+(a22*b22)+(a23*b32)+(a24*b42))/1000,¬
((a21*b13)+(a22*b23)+(a23*b33)+(a24*b43))/1000,¬
((a21*b14)+(a22*b24)+(a23*b34)+(a24*b44))/1000],¬
[((a31*b11)+(a32*b21)+(a33*b31)+(a34*b41))/1000,¬
((a31*b12)+(a32*b22)+(a33*b32)+(a34*b42))/1000,¬
((a31*b13)+(a32*b23)+(a33*b33)+(a34*b43))/1000,¬
((a31*b14)+(a32*b24)+(a33*b34)+(a34*b44))/1000],¬
[((a41*b11)+(a42*b21)+(a43*b31)+(a44*b41))/1000,¬
((a41*b12)+(a42*b22)+(a43*b32)+(a44*b42))/1000,¬
((a41*b13)+(a42*b23)+(a43*b33)+(a44*b43))/1000,¬
((a41*b14)+(a42*b24)+(a43*b34)+(a44*b44))/1000]]
  
end

--
-- Matrix4x4Mult takes two 4x4 matrices, multiples them and returns the 4x4 result.
--on Matrix4x4Mult a, b
--  
--  if count(a[1]) = count(b) then
--    put a[1][1] into a11
--    put a[2][1] into a21
--    put a[3][1] into a31
--    put a[4][1] into a41
--    put a[1][2] into a12
--    put a[2][2] into a22
--    put a[3][2] into a32
--    put a[4][2] into a42
--    put a[1][3] into a13
--    put a[2][3] into a23
--    put a[3][3] into a33
--    put a[4][3] into a43
--    put a[1][4] into a14
--    put a[2][4] into a24
--    put a[3][4] into a34
--    put a[4][4] into a44
--    put b[1][1] into b11
--    put b[2][1] into b21
--    put b[3][1] into b31
--    put b[4][1] into b41
--    put b[1][2] into b12
--    put b[2][2] into b22
--    put b[3][2] into b32
--    put b[4][2] into b42
--    put b[1][3] into b13
--    put b[2][3] into b23
--    put b[3][3] into b33
--    put b[4][3] into b43
--    put b[1][4] into b14
--    put b[2][4] into b24
--    put b[3][4] into b34
--    put b[4][4] into b44
--    return [¬
--[((a11*b11)+(a12*b21)+(a13*b31)+(a14*b41))/1000,¬
-- ((a11*b12)+(a12*b22)+(a13*b32)+(a14*b42))/1000,¬
-- ((a11*b13)+(a12*b23)+(a13*b33)+(a14*b43))/1000,¬
-- ((a11*b14)+(a12*b24)+(a13*b34)+(a14*b44))/1000],¬
--[((a21*b11)+(a22*b21)+(a23*b31)+(a24*b41))/1000,¬
-- ((a21*b12)+(a22*b22)+(a23*b32)+(a24*b42))/1000,¬
-- ((a21*b13)+(a22*b23)+(a23*b33)+(a24*b43))/1000,¬
-- ((a21*b14)+(a22*b24)+(a23*b34)+(a24*b44))/1000],¬
--[((a31*b11)+(a32*b21)+(a33*b31)+(a34*b41))/1000,¬
-- ((a31*b12)+(a32*b22)+(a33*b32)+(a34*b42))/1000,¬
-- ((a31*b13)+(a32*b23)+(a33*b33)+(a34*b43))/1000,¬
-- ((a31*b14)+(a32*b24)+(a33*b34)+(a34*b44))/1000],¬
--[((a41*b11)+(a42*b21)+(a43*b31)+(a44*b41))/1000,¬
-- ((a41*b12)+(a42*b22)+(a43*b32)+(a44*b42))/1000,¬
-- ((a41*b13)+(a42*b23)+(a43*b33)+(a44*b43))/1000,¬
-- ((a41*b14)+(a42*b24)+(a43*b34)+(a44*b44))/1000]]
--  else
--    put "Error: Could not multiply matrices, a.cols != b.rows != 4."
--    return 0
--  end if
--end

-- Matrix1x4Mult takes a 1x4 matrix as its first argument and a 4x4 matrix as its second argument
-- and multiplies them, returning the resulting 1x4 matrix.
on Matrix1x4Mult c, b
  if count(b[1]) = count(c) then
    a1 = integer(c[1]*1000)
    a2 = integer(c[2]*1000)
    a3 = integer(c[3]*1000)
    a4 = integer(c[4]*1000)
    
    return [¬
((b[1][1]*a1)+(b[1][2]*a2)+(b[1][3]*a3)+(b[1][4]*a4))/100000.0,¬
((b[2][1]*a1)+(b[2][2]*a2)+(b[2][3]*a3)+(b[2][4]*a4))/100000.0,¬
((b[3][1]*a1)+(b[3][2]*a2)+(b[3][3]*a3)+(b[3][4]*a4))/100000.0,¬
((b[4][1]*a1)+(b[4][2]*a2)+(b[4][3]*a3)+(b[4][4]*a4))/100000.0]
  else
    put "Error: Could not multiple matrices, a.cols != b.rows."
    return 0
  end if
end

-- location = x, y, z, intensity = r, g, b
-- creates a light and returns its unique ID in the lightingList
on createLight location, intensity
  set x = count(lightinglist)
  
  lightingList.addProp(x+1, [location[1], location[2], location[3], intensity[1], intensity[2], intensity[3]])
  
  return x
end

-- deletes a light
on deleteLight uniqueID
  lightingList.deleteProp(uniqueID)
end

on deleteAllLights
  lightinglist = [:]
end


on calculateIntensity polygon, lightingList   --, viewPoint
  set x = count(lightingList)
  repeat with i = 1 to x
    
    
    
  end repeat
  if x = 0 then return 0
end


on vGetViewingVector viewPoint, normalTail
  return( [0, 0, 1] )
end

-- vGetH takes the lighting vector and the viewing vector and returns the unit vector halfway between these two.
-- This is cheaper than using the exact reflection vector.
on vGetH l, v
  return vScalarMult(vAdd(l, v)*0.5)
end  

-- vGetReflectionVector takes the normal vector of a surface, n, and the incident lighting vector l,
-- and returns the reflected vector.
on vGetReflectionVector n, l
  return( vSubtract(vScalarMult(n, 2 * vDotProduct(n, l)), l) )
end

-- vGetLightingVector takes the coordinates of a light (4 element list) and a vertex (4 element list) and
-- returns a the lighting vector associated with them.
on vGetLightingVector light, normalTail
  return([light[1] - normalTail[1], light[2] - normalTail[2], light[3] - normalTail[3]])
end

-- vNormal takes three vertices (4 element lists) of a polygon (v2 being "between" v1 and v3) and returns
-- the normal vector to that polygon.
on vNormal v1, v2, v3
  -- convert vertices to two vectors
  nv1 = [v3[1] - v2[1], v3[2] - v2[2], v3[3] - v2[3]]
  nv2 = [v1[1] - v2[1], v1[2] - v2[2], v1[3] - v2[3]]
  -- calculate normal
  return(vCrossProduct(nv1, nv2))
end

-- vCrossProduct takes two vectors (3 element lists each) and returns their cross product (a 3 element list)
on vCrossProduct v, w
  return([v[2]*w[3] - v[3]*w[2], v[3]*w[1] - v[1]*w[3], v[1]*w[2] - v[2]*w[1]])
end

-- vDotProduct takes two vectors (3 element lists each) and returns their dot product
on vDotProduct v, w
  return(v[1]*w[1] + v[2]*w[2] + v[3]*w[3])
end

-- vScalarMult multiplies vector v by a scalar
on vScalarMult v, scalar
  return([v[1] * scalar, v[2] * scalar, v[3] * scalar])
end

-- vNormalize takes a vector and returns the normalize unit vector of that vector
on vNormalize v
  z = vMagnitude(v)
  return([v[1]/float(z[1]), v[2]/float(z[2]), v[3]/float(z[3])])
end

-- vMagnitude takes a vector and returns its magnitude
on vMagnitude v
  return(sqrt((v[1]*v[1] + v[2]*v[2] + v[3]*v[3])))
end

-- vAdd adds one vector to another
on vAdd v, w
  return([v[1] + w[1], v[2] + w[2], v[3] + w[3]])
end

-- vSubtract subtracts one vector from another
on vSubtract v, w
  return([v[1] - w[1], v[2] - w[2], v[3] - w[3]])
end

-- scaleRect takes a rect and scales the size of the rect based on the scalar coefficient
-- returns the new Rect()
on scaleRect oldrect, scalar
  --  set oldh = (the bottom of oldrect) - (the top of oldrect)
  --  set oldw = (the right of oldrect) - (the left of oldrect)
  
  set oldh = the height of oldrect
  set oldw = the width of oldrect
  
  set midw = (oldw/2)+the left of oldrect
  set midh = (oldh/2)+the top of oldrect
  
  set halfh = (scalar * oldh)/2
  set halfw = (scalar * oldw)/2
  
  return(Rect(midw - halfw, midh - halfh, midw + halfw, midh + halfh))
end


-- positionRect positions a rect centered at a point lH, lV
on positionRect oldrect, lH, lV
  
  set oldh2 = (the height of oldrect)/2
  set oldw2 = (the width of oldrect)/2
  
  return(Rect(lH - oldw2, lV - oldh2, lH + oldw2, lV + oldh2))
end

------------------------------------------------------------------------------
-- The functions below aren't used directly in Dave's 3D Engine, but are    --
-- provided for backwards compatibility with previous versions.             --
------------------------------------------------------------------------------

-- acos() - arccosine function (Thanks Hopper-Ex!)
-- takes values between -1 and 1, returns values between 0 and PI
on acos x
  if abs(x) > 1 then
    return 0
  else if x = 0 then
    return 0
  else
    return(atan(sqrt(1.0 - x*x)/float(x)))
  end if
end

-- asin() - arcsine function (Thanks Again Hopper-Ex!)
-- takes values between -1 and 1, returns values between -PI/2.0 and PI/2.0
on asin x
  if abs(x) > 1 then
    return void
  else if x = 1 then
    return(PI/2.0)
  else if x = -1 then
    return(-PI/2.0)
  else
    return atan(float(x)/sqrt(1.0 - x*x))
  end if
end asin


on floatDiv floatA, floatB
  return integer(floatA - 0.5) / integer(floatB - 0.5)
end

 


Contact

MMI
36 South Court Sq
Suite 300
Newnan, GA 30263
USA

Send e-mail