-- GOO -- -- -- © May 2001, James Newton -- PROPERTY DECLARATIONS -- property mySprite -- sprite(me.spriteNum) property myMember -- original member of mySprite (serves for image) property myImage -- intially, image of myMember property myBitmap -- temporary member to modify property myShape -- #concave | #convex property myRadius -- radius of bubble sphere (pixels) property myFacets -- number of facets along one edge of one quadrant -- (actual number of facets = 4*myFacets*myFacets) property myRectList -- list of rects for source images of facets property myQuadList -- list of quads for pasting the source images property myImageLoc -- current loc of the mouse(adjusted for sprite) -- SPRITE EVENTS -- on beginSprite(me) me.initialize() end beginSprite on endSprite(me) mySprite.member = myMember myBitmap.erase() end endSprite -- EVENT HANDLER -- on mouseDown(me) -- Uncomment the next line to save changes between mouse clicks myImage = myBitmap.image.duplicate() me.createBubble() end mouseDown on exitFrame(me) if ilk(myImageLoc, #point) then if the mouseDown then me.createBubble() else -- The user released the mouse myImageLoc = VOID end if end if end exitFrame -- PUBLIC METHODS -- on setRadius(me, radius) if integerP(radius) then if radius > 0 then myRadius = radius me.createSourceListAndQuadList() end if end if end setRadius on setFacets(me, facets) if integerP(facets) then if facets > 0 then myFacets = facets me.createSourceListAndQuadList() end if end if end setRadius on setBubbleShape(me, whichShape) case whichShape of #concave, #convex: myShape = whichShape me.createSourceListAndQuadList() end case end setBubbleShape -- PRIVATE METHODS -- on initialize(me) ---------------------------------------------------- -- Sent by beginSprite() -------------------------------------------------------------------- mySprite = sprite(me.spriteNum) myMember = mySprite.member myImage = myMember.image -- Modify a temporary bitmap member, not the original myBitmap = new(#bitmap) myBitmap.image = myImage mySprite.member = myBitmap -- Set default values for size and level of detail myFacets = 4 myRadius = 40 -- Create the permanent copy-from-rect and paste-into-quad lists me.createSourceListAndQuadList() end initialize on createBubble(me) -------------------------------------------------- -- Sent by mouseDown() and exitFrame() while the mouse is held down -- -- ACTION: Copies a distorted version of myImage into a temporary -- image object, which is then applied to the member of this sprite. -------------------------------------------------------------------- imageLoc = the mouseLoc - [mySprite.left, mySprite.top] if myImageLoc = imageLoc then -- We've already drawn the bubble here exit end if myImageLoc = imageLoc -- Create a list of source images bitmapImage = myImage.duplicate() -- use duplicate() for speed facetList = me.getFacetList(myImageLoc, bitmapImage) -- Copy the flat facet images to the appropriate distorting quad i = facetList.count repeat while i source = facetList[i] copyArea = source.rect pasteArea = me.getAdjustedQuad(myQuadList[i], myImageLoc) bitmapImage.copyPixels(source, pasteArea, copyArea) i = i - 1 end repeat -- Apply modified image to sprite myBitmap.image = bitmapImage end createBubble on createSourceListAndQuadList(me) ----------------------------------- -- Sent by initialize() -- -- ACTION: Creates two lists and stores them permanently as -- properties of this instance: -- * myRectList: defines the source rects for each facet -- * myQuadList: defines the quad into which each facet image is to -- be pasted -- These lists are templates: when the user clicks on the sprite, -- the data stored in the lists will need to be adjusted to take -- the current mouseLoc into account. The adjustments are carried -- out in the getFacetList() and getAdjustedQuad() handlers. -------------------------------------------------------------------- myRectList = [] myQuadList = [] -- Create a list of offsets from the center point, with which to -- create the grids. vertexPoints = [-myRadius] facetSize = myRadius / float(myFacets) i = myFacets * 2 repeat while i i = i - 1 vertexPoints.append(myRadius - integer(facetSize * i)) end repeat -- Example: vertexPoints = [40, 30, 20, 10, 0, -10, -20, -30, - 40] -- Iterate through vertexPoints, building the two grids counter = vertexPoints.count - 1 repeat with x = 1 to counter vLeft = vertexPoints[x] vRight = vertexPoints[x + 1] repeat with y = 1 to counter -- Generate the next rect for myRectList vTop = vertexPoints[y] vBottom = vertexPoints[y + 1] myRectList.append(rect(vLeft, vTop, vRight, vBottom)) -- Generate the next quad for myQuadList quadData = [] quadData.append(me.getQuadPoint(vLeft, vTop)) quadData.append(me.getQuadPoint(vRight, vTop)) quadData.append(me.getQuadPoint(vRight, vBottom)) quadData.append(me.getQuadPoint(vLeft, vBottom)) myQuadList.append(quadData) end repeat end repeat end createSourceListAndQuadList on getQuadPoint(me, hLoc, vLoc) -------------------------------------- -- Sent by createSourceListAndQuadList() -- -- PARAMETERS: -- and are integers -- -- RETURNS: a point -- -- ACTION: calculates where the point(hLoc, vLoc) would appear when -- mapped onto the bubble. If the point is outside the bubble, no -- alteration is made. -------------------------------------------------------------------- if myShape = #concave then -- "Burst" the bubble length2 = float(hLoc*hLoc + vLoc*vLoc) vLength = sqrt(length2) vHeight = sqrt(myRadius*myRadius - length2) if vHeight > 0 then angle = atan(vLength / vHeight) if vLength > 0 then pointOnCircumference = point(hLoc, vLoc) * myRadius / vLength else pointOnCircumference = point(hLoc, vLoc) end if else angle = pi / 2 pointOnCircumference = point(hLoc, vLoc) end if return pointOnCircumference * 2 * angle / pi else -- Create a standard bubble ratio = sqrt(float(hLoc*hLoc + vLoc*vLoc)) / myRadius if ratio > 0 and ratio < 1 then -- The point is on the surface of the sphere pointOnCircumference = point(hLoc, vLoc) / ratio arcRatio = sin(ratio * pi / 2) return pointOnCircumference * arcRatio else -- The point is under the mouse or outside the sphere return point(hLoc, vLoc) end if end if end getQuadPoint on getFacetList(me, imageLoc, bitmapImage) --------------------------- -- Sent by createBubble() -- -- PARAMETERS: -- is the point in the image currently under the mouse -- is the image before it is distorted -- -- ACTION: Adjusts the values of the myRectList. -------------------------------------------------------------------- facetList = myRectList.duplicate() hLoc = imageLoc.locH vLoc = imageLoc.locV imageWidth = myBitmap.width imageHeight = myBitmap.height i = facetList.count repeat while i facetRect = facetList[i] -- Ensure that facet rects are within the image facetRect.left = max(0, min(facetRect.left +hLoc, imageWidth)) facetRect.top = max(0, min(facetRect.top +vLoc, imageHeight)) facetRect.right = max(0, min(facetRect.right +hLoc, imageWidth)) facetRect.bottom = max(0, min(facetRect.bottom+vLoc, imageHeight)) facetList[i] = bitmapImage.crop(facetRect) i = i - 1 end repeat return facetList end getFacetList on getAdjustedQuad(me, quadData, quadOffset) ------------------------ -- Called by createBubble() -- -- PARAMETERS: -- is a quad list of 4 points -- is a point -- -- RETURNS: a quad ( offset by ) -------------------------------------------------------------------- adjustedQuad = [] repeat with i = 1 to 4 adjustedQuad.append(quadData[i] + quadOffset) end repeat return adjustedQuad end getAdjustedQuad