Sprite Sheet Renderer - Overview

Platform: 3ds Max 2010 (MAXScript)
Status: Released - V1.2.4
Address: www.GeoffSamuel.com/Scrip_Files.php?proj=4


This script is designed to help speed up the process of rendering out sprite sheets, allowing for:

  • the option to skip animation frames,
  • save out the sprite sheets automatically,
  • create sprite sheets from multiple camera views
  • as well as the option to compile all the views into a massive sprite sheet with pixel precision.

Code

------------------------------------------------------
--           Sprite Sheet Renderer             --
--         Created by Geoffrey Samuel          --
--        Email: Geoff@geoffsamuel.com        --
--       Website: www.geoffsamuel.com     --
--                (Version 1.2.4)                  --
------------------------------------------------------
------------------------------------------------------
------------------------------------------------------
/* LEGAL AND COPYRIGHT  INFO
------------------------------------------------------
Copyright (c) 2009-2010, Geoff Samuel
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

------------------------------------------------------
/* OTHER  INFO
------------------------------------------------------

It would be appreciate if the author could be informed to the use of the plugin/tool/code as to promote the usage of the plugin/tool/code.
Any modifications done to the plugin/tool/code for improved functionality or stability would be welcome as keep building off a single plugin/tool/code allowing for more people to benefit,
although this is not mandatory.

Bugs and feature requests to: Support@GeoffSamuel.com

------------------------------------------------------
/* BUILD AND VERSION INFO
------------------------------------------------------

Build date: 19/6/2010

Further features to be implemented: (build version 1.6)
* remove deadzones and creation of xml sprite information sheet

Version History: (build version 1.2.4)
* Added automaticly saving of images
* Added saveing formulars
* Added ablity to render out mulipul cameras onto a single sheet or seprately
* Sped up with thanks to Jameson Thatcher

Version History: (build version 1.2)
* User interface added
* Code cleaned up, made more dynamic with frame skip
* fixed bug causing frames to be out by 1 pixel
* fixed bug causing frames to be rendered with a black border
* Sped up with thanks to Jameson Thatcher


Version History: (build version 1.0)
* was used in 2009 game High School Bruisical
* hard coded skip frame function implemented
* Basic render and placement
* Project Started.

*/

--Function to parse the saving formular, takes the formular and the camera name
fn Formular_Translate formular cameraObj = (
    -- sets ups the tag name
    c = "<Camera_Name>"

    --look for the tag, if its not found, return the orginal text, otherwise replace the tag with the name of the camera object
    p = findString formular c
    if(p != undefined)do(
        formular = replace formular p c.count cameraObj
    )
    --return result
    return formular
)

--Main render sprite function. made into function so can be used with maxscript
fn Render_Sprite_sheet start stop jump camera_array method tobeoutputed outpath outname=(
   
    --new array to hold all the sprite sheets so to compile them all at the end.
    Sprite_Sheet = #()
   
    for o in camera_array do(
        --set up camera to render from
        case o of
        (          
        "Top View": viewport.setType #view_top
        "Bottom View": viewport.setType #view_bottom
        "Right View": viewport.setType #view_right
        "Left View": viewport.setType #view_left
        "Front View": viewport.setType #view_front
        "Back View": viewport.setType #view_back
        "Perspective View": viewport.setType #view_persp_user
        "Orthographic View": viewport.setType #view_iso_user           
           
        default: viewport.setCamera (execute ("$'"+o + "'"))
        )

   
        --render off test image for hight and width info
        complete_sprite = render vfb:false
        height = ((temp = getBitmapInfo complete_sprite)[4])
        width = ((temp = getBitmapInfo complete_sprite)[3])        
       
        --calculate width of final image
        complete_width = width *  ((stop - start)/jump+1)
        --new image with width and hight of final image
        bittemp = bitmap complete_width height

        --for loop to go through all the frames needed
        for q = 1 to (stop - start)/jump+1 do (
            --sets the frame time
             sliderTime = (start + ((q-1) * jump))
            --renderers frame and adds to array
            img=  render vfb:false
           
            --put the complete_sprite in the top left hand cornor
            for y = 0 to height do (
                --temp_pixels = getPixels img [0,y] width   
                setPixels bittemp [(q-1)*width,y] (getPixels img [0,y] width)
            )
        )
        --add to sprite sheet array for use later in complieing them all
        append Sprite_Sheet bittemp

    )
    --if wanting the sheet to be contain multpiul sheets or both
    if(method >= 2)do(
        --get height and width
        height = ((temp = getBitmapInfo Sprite_Sheet[1])[4])
        width = ((temp = getBitmapInfo Sprite_Sheet[1])[3])        
       
        --calculate height of final image
        complete_height = height *  Sprite_Sheet.count
        --new image with width and hight of final image
        bittemp = bitmap width complete_height
       
        --put the each of the sprites in the right hight place
        for q = 0 to Sprite_Sheet.count-1 do(
            for y = 0 to height  do(
                setPixels bittemp [0,y +(height*q) ] (getPixels Sprite_Sheet[q+1] [0,y] width)
            )
        )
        --if the image isnt being saved automaticly, display it otherwise work out file name and save it
        if(tobeoutputed == true)then(
            bittemp.filename = outpath + "//" + (Formular_Translate outname "Multiple_Camera")
            save bittemp
        )else(
            display bittemp
        )
    )
   
        -- if wanting to have sprite sheet sepreatly or both
        if(method == 1) or (method == 3)do(
   
            for i = 1 to Sprite_Sheet.count do(
               
                --go though and work with each image in the sprite sheet array
                bittemp = Sprite_Sheet[i]
           
                --if the image isnt being saved automaticly, display it otherwise work out file name and save it
                if(tobeoutputed == true)then(
                    bittemp.filename = outpath + "//" +(Formular_Translate outname camera_array[i])
                    save bittemp
                )else(
                    display bittemp
                )
            )
        )
   
   
   
   
   
)


--User interface - contains no comments
rollout about_rollout "About" width:320 height:106
(
    label lbl1 "Created by:" pos:[9,26] width:59 height:17
    label lbl2 "Sprite Render" pos:[125,2] width:70 height:15
    label lbl3 "Geoffrey Samuel" pos:[70,27] width:175 height:14
    label lbl4 "Website:" pos:[9,42] width:59 height:17
    label lbl5 "www.GeoffSamuel.com" pos:[71,43] width:175 height:14
    label lbl6 "Email:" pos:[9,58] width:59 height:17
    label lbl7 "Geoff@GeoffSamuel.com" pos:[70,59] width:175 height:14
    label lbl8 "Build Date:" pos:[199,73] width:54 height:14
    label lbl9 "Build Num:" pos:[199,88] width:54 height:14
    label lbl10 "1.2.4" pos:[255,87] width:53 height:13
    label lbl11 "19/6/2010" pos:[255,73] width:53 height:13
)

rollout Main_rollout "Options" width:340 height:551
(
    button go_button "GO!" pos:[11,310] width:299 height:42
    spinner start_spinner "" pos:[108,16] width:57 height:16 range:[-99999,99999,0] type:#integer
    spinner stop_spinner "" pos:[107,47] width:57 height:16 range:[-99999,99999,0] type:#integer
    spinner jump_spinner "" pos:[107,80] width:57 height:16 range:[0,99999,0] type:#integer
    label lbl34 "Frame Start" pos:[35,16] width:64 height:16
    label lbl35 "Frame Stop" pos:[35,48] width:64 height:16
    label lbl36 "Every Nth Frame" pos:[11,80] width:88 height:16
    multiListBox cams_in_Scene "Cameras to Render:" pos:[13,220] width:297 height:4
    GroupBox grp1 "Method" pos:[174,12] width:136 height:83
    radiobuttons method "" pos:[182,29] width:102 height:48 labels:#("Separate Sheets", "Multiple Lines", "Both") columns:1
    GroupBox grp2 "Output" pos:[8,99] width:302 height:118
    edittext Filename_Form "" pos:[10,156] width:289 height:18 text:"<Camera_Name>_.PNG"
    edittext output_path "" pos:[10,193] width:238 height:18
    button Browse_button "Browse" pos:[253,192] width:47 height:20
    label lbl10 "Filename Formular:" pos:[18,141] width:181 height:12
    label lbl11 "Output Path:" pos:[18,176] width:181 height:15
    checkbox outputCheckbox "Output to file" pos:[19,119] width:242 height:16 checked:true

    on Main_rollout open do
    (
            start_spinner.value  = ((animationRange.start) as integer )/ TicksPerFrame as integer
            stop_spinner.value  = ((animationRange.end) as integer )/ TicksPerFrame as integer
            jump_spinner.value = 1
            arr = #("Top View","Back View","Front View","Left View","Bottom View","Right View","Orthographic View","Perspective View")
            for o in cameras do(
                if(findString o.name ".Target" == undefined)do(
                    append arr o.name
                )
            )
            cams_in_Scene.items = arr
    )
    on go_button pressed do
    (
        cam_array = cams_in_Scene.selection as array
        for i = 1 to cam_array.count do(
            cam_array[i] = cams_in_Scene.items[cam_array[i]]
        )
       
        Render_Sprite_sheet start_spinner.value stop_spinner.value jump_spinner.value cam_array Method.state outputCheckbox.checked output_path.text Filename_Form.text
    )
    on Browse_button pressed do
    (
        t = getSavePath()
        if(t != undefined)do(
            output_path.text = t
        )
    )
)


function MakerolloutFloat =
(
    if undefined != SpriteRenderFloater then closeRolloutFloater SpriteRenderFloater
    SpriteRenderFloater = newRolloutFloater "Sprite Render" 330 520
    addRollout about_rollout SpriteRenderFloater rolledup:false
    addRollout Main_rollout SpriteRenderFloater rolledup:false
)


MakerolloutFloat()

Script Download

The script can be downloaded here