├── psd └── test.psd ├── CPM ├── config.lua ├── build.settings ├── ui.lua └── director.lua ├── README └── src └── CoronaDirectorExporter_newMerge.jsx /psd/test.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevcjones-archived/Photoshop-to-Corona-Exporter/HEAD/psd/test.psd -------------------------------------------------------------------------------- /CPM/config.lua: -------------------------------------------------------------------------------- 1 | -- config.lua for project: ExportImages 2 | -- Managed with http://CoronaProjectManager.com 3 | -- Copyright 2011 Kevin Jones. All Rights Reserved. 4 | -- cpmgen config.lua 5 | application = 6 | { 7 | content = 8 | { 9 | width = 320, 10 | height = 480, 11 | scale = "zoomEven", 12 | fps = 30, 13 | antialias = false, 14 | xalign = "center", 15 | yalign = "center" 16 | } 17 | } -------------------------------------------------------------------------------- /CPM/build.settings: -------------------------------------------------------------------------------- 1 | -- build.settings for project: ExportImages 2 | -- Managed with http://CoronaProjectManager.com 3 | -- Copyright 2011 Kevin Jones. All Rights Reserved. 4 | -- cpmgen build.settings 5 | settings = 6 | { 7 | orientation = 8 | { 9 | default ="landscapeLeft", 10 | content = "landscapeLeft", 11 | supported = 12 | { 13 | "landscapeLeft","landscapeRight" 14 | }, 15 | }, 16 | 17 | } 18 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | For running conversation goto http://developer.anscamobile.com/forum/2011/03/28/new-psd-lua-png-exporter-using-directorlua 3 | 4 | /* The MIT License Copyright (c) 2011 Kevin C Jones aka @KevCJones aka him@kevincjones.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Corona Director Exporter ---------------------------------- I will assume people right now know how to drop run a JSX. Google it. You will see something about puttin it into \Presets\Scripts and relaunching Photoshop.. there i practically did it for you :) Converts a layered PSD into a main.lua + and scenes along with an assets folder for all images used in the layout as seperate usable assets. I use templates in the script which are direct copies and make good use of the String.replace(what,with) js function. As we grow these $hooks to inject code can be easily expanded to support more and more complex jobs. The challenge will be finding nice ways to put them into the layers. Currently we make good use of keyterms in the name to help the exported identiy what to treat that layer as. These keyterms are removed once detected and not included in filenames and variable names for the objects they generate. e.g, myscene_scene strips _scene_ and calls the local scene file 'myscene.lua'. Keyterms: + _scene_ in layers on the root is the scene files themselves. + _button_ in group layers will beging creating a button in the scene and look inside the group for : - _default_ for the image used as the default state of the button (UI.lua) - _touch_ for the touch image. + _merge_ on groups will merge normal group layers into flat images and create single local variables to reference the image Note : If _touch_ or _default_ is the name of a group not a layer then that group is merged and saved as a single image as you would expect. Contributors ----------------- So far just me :) but I hope to involve everyone. These things tend to do the best when they have a following and people care about the code as well. I hope that we can keep it clean, readable and maintainable as we grow it, I will be adding it into Github sooner rather than later. With any luck the great guys at Corona will see fit to bundle it in the installer package and offer us all promotion codes for our efforts ;) ;) such rewards are merely a bonus... To Do: --------- - Add Sprite Sheet / MovieClip support - Add Basic Entry Animations (tweenfrombottom, top, left, right etc) Known Issues ------------------- - I added padding because in Corona i was seeing a glitch in the simulator for left hand edges which touched the screen. We should test with and without this on hardware to see if it is purely a scaling issue on the simulator or if there is an issue with the rendering, Padding is all sides and will auto offset the X,Y coord by -padding, -padding to compensate the invisible bordering. - Duplicated Graphics - I added code to stop accidental occurances but then there are cases where i want it to happen... will added in about condition to make this work neatly. */ -------------------------------------------------------------------------------- /CPM/ui.lua: -------------------------------------------------------------------------------- 1 | -- ui.lua (currently includes Button class with labels, font selection and optional event model) 2 | 3 | -- Version 1.5 (works with multitouch, adds setText() method to buttons) 4 | -- 5 | -- Copyright (C) 2010 ANSCA Inc. All Rights Reserved. 6 | -- 7 | -- Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | -- this software and associated documentation files (the "Software"), to deal in the 9 | -- Software without restriction, including without limitation the rights to use, copy, 10 | -- modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 11 | -- and to permit persons to whom the Software is furnished to do so, subject to the 12 | -- following conditions: 13 | -- 14 | -- The above copyright notice and this permission notice shall be included in all copies 15 | -- or substantial portions of the Software. 16 | -- 17 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 18 | -- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | -- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 20 | -- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21 | -- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | -- DEALINGS IN THE SOFTWARE. 23 | 24 | ---------------------------------------------------- 25 | -- Edited by William Flagello, williamflagello.com 26 | ---------------------------------------------------- 27 | -- Works with Dynamic Scaling. 28 | ---------------------------------------------------- 29 | 30 | module(..., package.seeall) 31 | 32 | ----------------- 33 | -- Helper function for newButton utility function below 34 | local function newButtonHandler( self, event ) 35 | 36 | local result = true 37 | 38 | local default = self[1] 39 | local over = self[2] 40 | 41 | -- General "onEvent" function overrides onPress and onRelease, if present 42 | local onEvent = self._onEvent 43 | 44 | local onPress = self._onPress 45 | local onRelease = self._onRelease 46 | 47 | local buttonEvent = {} 48 | if (self._id) then 49 | buttonEvent.id = self._id 50 | end 51 | 52 | local phase = event.phase 53 | if "began" == phase then 54 | if over then 55 | default.isVisible = false 56 | over.isVisible = true 57 | end 58 | 59 | if onEvent then 60 | buttonEvent.phase = "press" 61 | result = onEvent( buttonEvent ) 62 | elseif onPress then 63 | result = onPress( event ) 64 | end 65 | 66 | -- Subsequent touch events will target button even if they are outside the stageBounds of button 67 | display.getCurrentStage():setFocus( self, event.id ) 68 | self.isFocus = true 69 | 70 | elseif self.isFocus then 71 | local bounds = self.stageBounds 72 | local x,y = event.x,event.y 73 | local isWithinBounds = 74 | bounds.xMin <= x and bounds.xMax >= x and bounds.yMin <= y and bounds.yMax >= y 75 | 76 | if "moved" == phase then 77 | if over then 78 | -- The rollover image should only be visible while the finger is within button's stageBounds 79 | default.isVisible = not isWithinBounds 80 | over.isVisible = isWithinBounds 81 | end 82 | 83 | elseif "ended" == phase or "cancelled" == phase then 84 | if over then 85 | default.isVisible = true 86 | over.isVisible = false 87 | end 88 | 89 | if "ended" == phase then 90 | -- Only consider this a "click" if the user lifts their finger inside button's stageBounds 91 | if isWithinBounds then 92 | if onEvent then 93 | buttonEvent.phase = "release" 94 | result = onEvent( buttonEvent ) 95 | elseif onRelease then 96 | result = onRelease( event ) 97 | end 98 | end 99 | end 100 | 101 | -- Allow touch events to be sent normally to the objects they "hit" 102 | display.getCurrentStage():setFocus( self, nil ) 103 | self.isFocus = false 104 | end 105 | end 106 | 107 | return result 108 | end 109 | 110 | 111 | --------------- 112 | -- Button class 113 | 114 | function newButton( params ) 115 | local button, defaultSrc , defaultX , defaultY , overSrc , overX , overY , size, font, textColor, offset 116 | 117 | if params.defaultSrc then 118 | button = display.newGroup() 119 | default = display.newImageRect ( params.defaultSrc , params.defaultX , params.defaultY ) 120 | button:insert( default, true ) 121 | end 122 | 123 | if params.overSrc then 124 | over = display.newImageRect ( params.overSrc , params.overX , params.overY ) 125 | over.isVisible = false 126 | button:insert( over, true ) 127 | end 128 | 129 | -- Public methods 130 | function button:setText( newText ) 131 | 132 | local labelText = self.text 133 | if ( labelText ) then 134 | labelText:removeSelf() 135 | self.text = nil 136 | end 137 | 138 | local labelShadow = self.shadow 139 | if ( labelShadow ) then 140 | labelShadow:removeSelf() 141 | self.shadow = nil 142 | end 143 | 144 | local labelHighlight = self.highlight 145 | if ( labelHighlight ) then 146 | labelHighlight:removeSelf() 147 | self.highlight = nil 148 | end 149 | 150 | if ( params.size and type(params.size) == "number" ) then size=params.size else size=20 end 151 | if ( params.font ) then font=params.font else font=native.systemFontBold end 152 | if ( params.textColor ) then textColor=params.textColor else textColor={ 255, 255, 255, 255 } end 153 | 154 | -- Optional vertical correction for fonts with unusual baselines (I'm looking at you, Zapfino) 155 | if ( params.offset and type(params.offset) == "number" ) then offset=params.offset else offset = 0 end 156 | 157 | if ( params.emboss ) then 158 | -- Make the label text look "embossed" (also adjusts effect for textColor brightness) 159 | local textBrightness = ( textColor[1] + textColor[2] + textColor[3] ) / 3 160 | 161 | labelHighlight = display.newText( newText, 0, 0, font, size ) 162 | if ( textBrightness > 127) then 163 | labelHighlight:setTextColor( 255, 255, 255, 20 ) 164 | else 165 | labelHighlight:setTextColor( 255, 255, 255, 140 ) 166 | end 167 | button:insert( labelHighlight, true ) 168 | labelHighlight.x = labelHighlight.x + 1.5; labelHighlight.y = labelHighlight.y + 1.5 + offset 169 | self.highlight = labelHighlight 170 | 171 | labelShadow = display.newText( newText, 0, 0, font, size ) 172 | if ( textBrightness > 127) then 173 | labelShadow:setTextColor( 0, 0, 0, 128 ) 174 | else 175 | labelShadow:setTextColor( 0, 0, 0, 20 ) 176 | end 177 | button:insert( labelShadow, true ) 178 | labelShadow.x = labelShadow.x - 1; labelShadow.y = labelShadow.y - 1 + offset 179 | self.shadow = labelShadow 180 | end 181 | 182 | labelText = display.newText( newText, 0, 0, font, size ) 183 | labelText:setTextColor( textColor[1], textColor[2], textColor[3], textColor[4] ) 184 | button:insert( labelText, true ) 185 | labelText.y = labelText.y + offset 186 | self.text = labelText 187 | end 188 | 189 | if params.text then 190 | button:setText( params.text ) 191 | end 192 | 193 | if ( params.onPress and ( type(params.onPress) == "function" ) ) then 194 | button._onPress = params.onPress 195 | end 196 | if ( params.onRelease and ( type(params.onRelease) == "function" ) ) then 197 | button._onRelease = params.onRelease 198 | end 199 | 200 | if (params.onEvent and ( type(params.onEvent) == "function" ) ) then 201 | button._onEvent = params.onEvent 202 | end 203 | 204 | -- Set button as a table listener by setting a table method and adding the button as its own table listener for "touch" events 205 | button.touch = newButtonHandler 206 | button:addEventListener( "touch", button ) 207 | 208 | if params.x then 209 | button.x = params.x 210 | end 211 | 212 | if params.y then 213 | button.y = params.y 214 | end 215 | 216 | if params.id then 217 | button._id = params.id 218 | end 219 | 220 | return button 221 | end 222 | 223 | 224 | -------------- 225 | -- Label class 226 | 227 | function newLabel( params ) 228 | local labelText 229 | local size, font, textColor, align 230 | local t = display.newGroup() 231 | 232 | if ( params.bounds ) then 233 | local bounds = params.bounds 234 | local left = bounds[1] 235 | local top = bounds[2] 236 | local width = bounds[3] 237 | local height = bounds[4] 238 | 239 | if ( params.size and type(params.size) == "number" ) then size=params.size else size=20 end 240 | if ( params.font ) then font=params.font else font=native.systemFontBold end 241 | if ( params.textColor ) then textColor=params.textColor else textColor={ 255, 255, 255, 255 } end 242 | if ( params.offset and type(params.offset) == "number" ) then offset=params.offset else offset = 0 end 243 | if ( params.align ) then align = params.align else align = "center" end 244 | 245 | if ( params.text ) then 246 | labelText = display.newText( params.text, 0, 0, font, size ) 247 | labelText:setTextColor( textColor[1], textColor[2], textColor[3], textColor[4] ) 248 | t:insert( labelText ) 249 | -- TODO: handle no-initial-text case by creating a field with an empty string? 250 | 251 | if ( align == "left" ) then 252 | labelText.x = left + labelText.stageWidth * 0.5 253 | elseif ( align == "right" ) then 254 | labelText.x = (left + width) - labelText.stageWidth * 0.5 255 | else 256 | labelText.x = ((2 * left) + width) * 0.5 257 | end 258 | end 259 | 260 | labelText.y = top + labelText.stageHeight * 0.5 261 | 262 | -- Public methods 263 | function t:setText( newText ) 264 | if ( newText ) then 265 | labelText.text = newText 266 | 267 | if ( "left" == align ) then 268 | labelText.x = left + labelText.stageWidth / 2 269 | elseif ( "right" == align ) then 270 | labelText.x = (left + width) - labelText.stageWidth / 2 271 | else 272 | labelText.x = ((2 * left) + width) / 2 273 | end 274 | end 275 | end 276 | 277 | function t:setTextColor( r, g, b, a ) 278 | local newR = 255 279 | local newG = 255 280 | local newB = 255 281 | local newA = 255 282 | 283 | if ( r and type(r) == "number" ) then newR = r end 284 | if ( g and type(g) == "number" ) then newG = g end 285 | if ( b and type(b) == "number" ) then newB = b end 286 | if ( a and type(a) == "number" ) then newA = a end 287 | 288 | labelText:setTextColor( r, g, b, a ) 289 | end 290 | end 291 | 292 | -- Return instance (as display group) 293 | return t 294 | 295 | end -------------------------------------------------------------------------------- /CPM/director.lua: -------------------------------------------------------------------------------- 1 | module(..., package.seeall) 2 | 3 | --====================================================================-- 4 | -- DIRECTOR CLASS 5 | --====================================================================-- 6 | -- 7 | -- Version: 1.2 8 | -- Made by Ricardo Rauber Pereira @ 2010 9 | -- Blog: http://rauberlabs.blogspot.com/ 10 | -- Mail: ricardorauber@gmail.com 11 | -- 12 | -- This class is free to use, feel free to change but please send new versions 13 | -- or new features like new effects to me and help us to make it better! 14 | -- 15 | --====================================================================-- 16 | -- CHANGES 17 | --====================================================================-- 18 | -- 19 | -- 06-OCT-2010 - Ricardo Rauber - Created 20 | -- 07-OCT-2010 - Ricardo Rauber - Functions loadScene and fxEnded were 21 | -- taken off from the changeScene function; 22 | -- Added function cleanGroups for best 23 | -- memory clean up; 24 | -- Added directorView and effectView groups 25 | -- for better and easier control; 26 | -- Please see INFORMATION to know how to use it 27 | -- 14-NOV-2010 - Ricardo Rauber - Bux fixes and new getScene function to get 28 | -- the name of the active scene (lua file) 29 | -- 14-FEB-2011 - Ricardo Rauber - General Bug Fixes 30 | -- 31 | --====================================================================-- 32 | -- INFORMATION 33 | --====================================================================-- 34 | -- 35 | -- * For best practices, use fps=60, scale = "zoomStretch" on config.lua 36 | -- 37 | -- * In main.lua file, you have to import the class like this: 38 | -- 39 | -- director = require( "director" ) 40 | -- local mainGroup = display.newGroup() 41 | -- mainGroup:insert( director.directorView ) 42 | -- 43 | -- * To change scenes, use this command [use the effect of your choice] 44 | -- 45 | -- director:changeScene("settings","moveFromLeft") 46 | -- 47 | -- * Every scene is a lua module file and must have a new() function that 48 | -- must return a local display group, like this: [see template.lua] 49 | -- 50 | -- module(..., package.seeall) 51 | -- local localGroup = display.newGroup() 52 | -- function new() 53 | -- ------ Your code here ------ 54 | -- return localGroup 55 | -- end 56 | -- 57 | -- * Every display object must be inserted on the local display group 58 | -- 59 | -- local background = display.newImage( "background.png" ) 60 | -- localGroup:insert( background ) 61 | -- 62 | -- * This class doesn't clean timers! If you want to stop timers when 63 | -- change scenes, you'll have to do it manually creating a clean() function. 64 | -- 65 | --====================================================================-- 66 | 67 | directorView = display.newGroup() 68 | currView = display.newGroup() 69 | nextView = display.newGroup() 70 | effectView = display.newGroup() 71 | -- 72 | local currScreen, nextScreen 73 | local currScene, nextScene = "main", "main" 74 | local newScene 75 | local fxTime = 200 76 | local safeDelay = 50 77 | local isChangingScene = false 78 | -- 79 | directorView:insert(currView) 80 | directorView:insert(nextView) 81 | directorView:insert(effectView) 82 | -- 83 | currView.x = 0 84 | currView.y = 0 85 | nextView.x = display.contentWidth 86 | nextView.y = 0 87 | 88 | ------------------------------------------------------------------------ 89 | -- GET COLOR 90 | ------------------------------------------------------------------------ 91 | 92 | local function getColor ( arg1, arg2, arg3 ) 93 | -- 94 | local r, g, b 95 | -- 96 | if type(arg1) == "nil" then 97 | arg1 = "black" 98 | end 99 | -- 100 | if string.lower(arg1) == "red" then 101 | r=255 102 | g=0 103 | b=0 104 | elseif string.lower(arg1) == "green" then 105 | r=0 106 | g=255 107 | b=0 108 | elseif string.lower(arg1) == "blue" then 109 | r=0 110 | g=0 111 | b=255 112 | elseif string.lower(arg1) == "yellow" then 113 | r=255 114 | g=255 115 | b=0 116 | elseif string.lower(arg1) == "pink" then 117 | r=255 118 | g=0 119 | b=255 120 | elseif string.lower(arg1) == "white" then 121 | r=255 122 | g=255 123 | b=255 124 | elseif type (arg1) == "number" 125 | and type (arg2) == "number" 126 | and type (arg3) == "number" then 127 | r=arg1 128 | g=arg2 129 | b=arg3 130 | else 131 | r=0 132 | g=0 133 | b=0 134 | end 135 | -- 136 | return r, g, b 137 | -- 138 | end 139 | 140 | ------------------------------------------------------------------------ 141 | -- CHANGE CONTROLS 142 | ------------------------------------------------------------------------ 143 | 144 | -- fxTime 145 | function director:changeFxTime ( newFxTime ) 146 | if type(newFxTime) == "number" then 147 | fxTime = newFxTime 148 | end 149 | end 150 | 151 | -- safeDelay 152 | function director:changeSafeDelay ( newSafeDelay ) 153 | if type(newSafeDelay) == "number" then 154 | safeDelay = newSafeDelay 155 | end 156 | end 157 | 158 | ------------------------------------------------------------------------ 159 | -- GET SCENES 160 | ------------------------------------------------------------------------ 161 | 162 | function director:getCurrScene () 163 | return currScene 164 | end 165 | -- 166 | function director:getNextScene () 167 | return nextScene 168 | end 169 | 170 | ------------------------------------------------------------------------ 171 | -- CLEAN GROUP 172 | ------------------------------------------------------------------------ 173 | 174 | local function cleanGroups ( curGroup, level ) 175 | if curGroup.numChildren then 176 | while curGroup.numChildren > 0 do 177 | cleanGroups ( curGroup[curGroup.numChildren], level+1 ) 178 | end 179 | if level > 0 then 180 | curGroup:removeSelf() 181 | end 182 | else 183 | curGroup:removeSelf() 184 | curGroup = nil 185 | return true 186 | end 187 | end 188 | 189 | ------------------------------------------------------------------------ 190 | -- CALL CLEAN FUNCTION 191 | ------------------------------------------------------------------------ 192 | 193 | local function callClean ( moduleName ) 194 | if type(package.loaded[moduleName]) == "table" then 195 | if string.lower(moduleName) ~= "main" then 196 | for k,v in pairs(package.loaded[moduleName]) do 197 | if k == "clean" and type(v) == "function" then 198 | package.loaded[moduleName].clean() 199 | end 200 | end 201 | end 202 | end 203 | end 204 | 205 | ------------------------------------------------------------------------ 206 | -- UNLOAD SCENE 207 | ------------------------------------------------------------------------ 208 | 209 | local function unloadScene ( moduleName ) 210 | if moduleName ~= "main" and type(package.loaded[moduleName]) == "table" then 211 | package.loaded[moduleName] = nil 212 | local function garbage ( event ) 213 | collectgarbage("collect") 214 | end 215 | garbage() 216 | timer.performWithDelay(fxTime,garbage) 217 | end 218 | end 219 | 220 | ------------------------------------------------------------------------ 221 | -- LOAD SCENE 222 | ------------------------------------------------------------------------ 223 | 224 | local function loadScene ( moduleName, target ) 225 | 226 | -- Test parameters 227 | if type(moduleName) == "nil" then 228 | return true 229 | end 230 | if type(target) == "nil" then 231 | target = "next" 232 | end 233 | 234 | ------------------------------------- 235 | -- Load choosed scene 236 | ------------------------------------- 237 | 238 | -- Prev 239 | if string.lower(target) == "curr" then 240 | -- 241 | callClean ( moduleName ) 242 | -- 243 | cleanGroups(currView,0) 244 | -- 245 | if nextScene == moduleName then 246 | cleanGroups(nextView,0) 247 | end 248 | -- 249 | unloadScene( moduleName ) 250 | -- 251 | currScreen = require(moduleName).new() 252 | currView:insert(currScreen) 253 | currScene = moduleName 254 | 255 | -- Next 256 | else 257 | -- 258 | callClean ( moduleName ) 259 | -- 260 | cleanGroups(nextView,0) 261 | -- 262 | if currScene == moduleName then 263 | cleanGroups(currView,0) 264 | end 265 | -- 266 | unloadScene( moduleName ) 267 | -- 268 | nextScreen = require(moduleName).new() 269 | nextView:insert(nextScreen) 270 | nextScene = moduleName 271 | 272 | end 273 | 274 | end 275 | 276 | -- Load curr screen 277 | function director:loadCurrScene ( moduleName ) 278 | loadScene ( moduleName, "curr" ) 279 | end 280 | 281 | -- Load next screen 282 | function director:loadNextScene ( moduleName ) 283 | loadScene ( moduleName, "next" ) 284 | end 285 | 286 | ------------------------------------------------------------------------ 287 | -- EFFECT ENDED 288 | ------------------------------------------------------------------------ 289 | 290 | local function fxEnded ( event ) 291 | 292 | currView.x = 0 293 | currView.y = 0 294 | currView.xScale = 1 295 | currView.yScale = 1 296 | -- 297 | callClean ( currScene ) 298 | cleanGroups( currView ,0) 299 | unloadScene( currScene ) 300 | -- 301 | currScreen = nextScreen 302 | currScene = newScene 303 | currView:insert(currScreen) 304 | -- 305 | nextView.x = display.contentWidth 306 | nextView.y = 0 307 | nextView.xScale = 1 308 | nextView.yScale = 1 309 | -- 310 | isChangingScene = false 311 | 312 | end 313 | 314 | ------------------------------------------------------------------------ 315 | -- CHANGE SCENE 316 | ------------------------------------------------------------------------ 317 | 318 | function director:changeScene(nextLoadScene, 319 | effect, 320 | arg1, 321 | arg2, 322 | arg3) 323 | 324 | ----------------------------------- 325 | -- If is changing scene, return without do anything 326 | ----------------------------------- 327 | 328 | if isChangingScene then 329 | return true 330 | else 331 | isChangingScene = true 332 | end 333 | 334 | ----------------------------------- 335 | -- If is the same, don't change 336 | ----------------------------------- 337 | 338 | if currScene then 339 | if string.lower(currScene) == string.lower(nextLoadScene) then 340 | return true 341 | end 342 | end 343 | 344 | newScene = nextLoadScene 345 | local showFx 346 | 347 | ----------------------------------- 348 | -- EFFECT: Move From Right 349 | ----------------------------------- 350 | 351 | if effect == "moveFromRight" then 352 | 353 | nextView.x = display.contentWidth 354 | nextView.y = 0 355 | -- 356 | loadScene (newScene) 357 | -- 358 | showFx = transition.to ( nextView, { x=0, time=fxTime } ) 359 | showFx = transition.to ( currView, { x=display.contentWidth*-1, time=fxTime } ) 360 | -- 361 | timer.performWithDelay( fxTime+safeDelay, fxEnded ) 362 | 363 | ----------------------------------- 364 | -- EFFECT: Over From Right 365 | ----------------------------------- 366 | 367 | elseif effect == "overFromRight" then 368 | 369 | nextView.x = display.contentWidth 370 | nextView.y = 0 371 | -- 372 | loadScene (newScene) 373 | -- 374 | showFx = transition.to ( nextView, { x=0, time=fxTime } ) 375 | -- 376 | timer.performWithDelay( fxTime+safeDelay, fxEnded ) 377 | 378 | ----------------------------------- 379 | -- EFFECT: Move From Left 380 | ----------------------------------- 381 | 382 | elseif effect == "moveFromLeft" then 383 | 384 | nextView.x = display.contentWidth*-1 385 | nextView.y = 0 386 | -- 387 | loadScene (newScene) 388 | -- 389 | showFx = transition.to ( nextView, { x=0, time=fxTime } ) 390 | showFx = transition.to ( currView, { x=display.contentWidth, time=fxTime } ) 391 | -- 392 | timer.performWithDelay( fxTime+safeDelay, fxEnded ) 393 | 394 | ----------------------------------- 395 | -- EFFECT: Over From Left 396 | ----------------------------------- 397 | 398 | elseif effect == "overFromLeft" then 399 | 400 | nextView.x = display.contentWidth*-1 401 | nextView.y = 0 402 | -- 403 | loadScene (newScene) 404 | -- 405 | showFx = transition.to ( nextView, { x=0, time=fxTime } ) 406 | -- 407 | timer.performWithDelay( fxTime+safeDelay, fxEnded ) 408 | 409 | ----------------------------------- 410 | -- EFFECT: Move From Top 411 | ----------------------------------- 412 | 413 | elseif effect == "moveFromTop" then 414 | 415 | nextView.x = 0 416 | nextView.y = display.contentHeight*-1 417 | -- 418 | loadScene (newScene) 419 | -- 420 | showFx = transition.to ( nextView, { y=0, time=fxTime } ) 421 | showFx = transition.to ( currView, { y=display.contentHeight, time=fxTime } ) 422 | -- 423 | timer.performWithDelay( fxTime+safeDelay, fxEnded ) 424 | 425 | ----------------------------------- 426 | -- EFFECT: Over From Top 427 | ----------------------------------- 428 | 429 | elseif effect == "overFromTop" then 430 | 431 | nextView.x = 0 432 | nextView.y = display.contentHeight*-1 433 | -- 434 | loadScene (newScene) 435 | -- 436 | showFx = transition.to ( nextView, { y=0, time=fxTime } ) 437 | -- 438 | timer.performWithDelay( fxTime+safeDelay, fxEnded ) 439 | 440 | ----------------------------------- 441 | -- EFFECT: Move From Bottom 442 | ----------------------------------- 443 | 444 | elseif effect == "moveFromBottom" then 445 | 446 | nextView.x = 0 447 | nextView.y = display.contentHeight 448 | -- 449 | loadScene (newScene) 450 | -- 451 | showFx = transition.to ( nextView, { y=0, time=fxTime } ) 452 | showFx = transition.to ( currView, { y=display.contentHeight*-1, time=fxTime } ) 453 | -- 454 | timer.performWithDelay( fxTime+safeDelay, fxEnded ) 455 | 456 | ----------------------------------- 457 | -- EFFECT: Over From Bottom 458 | ----------------------------------- 459 | 460 | elseif effect == "overFromBottom" then 461 | 462 | nextView.x = 0 463 | nextView.y = display.contentHeight 464 | -- 465 | loadScene (newScene) 466 | -- 467 | showFx = transition.to ( nextView, { y=0, time=fxTime } ) 468 | -- 469 | timer.performWithDelay( fxTime+safeDelay, fxEnded ) 470 | 471 | ----------------------------------- 472 | -- EFFECT: Crossfade 473 | ----------------------------------- 474 | 475 | elseif effect == "crossfade" then 476 | 477 | nextView.x = display.contentWidth 478 | nextView.y = 0 479 | -- 480 | loadScene (newScene) 481 | -- 482 | nextView.alpha = 0 483 | nextView.x = 0 484 | -- 485 | showFx = transition.to ( nextView, { alpha=1, time=fxTime*2 } ) 486 | -- 487 | timer.performWithDelay( fxTime*2+safeDelay, fxEnded ) 488 | 489 | ----------------------------------- 490 | -- EFFECT: Fade 491 | ----------------------------------- 492 | -- ARG1 = color [string] 493 | ----------------------------------- 494 | -- ARG1 = red [number] 495 | -- ARG2 = green [number] 496 | -- ARG3 = blue [number] 497 | ----------------------------------- 498 | 499 | elseif effect == "fade" then 500 | 501 | local r, g, b = getColor ( arg1, arg2, arg3 ) 502 | -- 503 | nextView.x = display.contentWidth 504 | nextView.y = 0 505 | -- 506 | loadScene (newScene) 507 | -- 508 | local fade = display.newRect( 0 - display.contentWidth, 0 - display.contentHeight, display.contentWidth * 3, display.contentHeight * 3 ) 509 | fade.alpha = 0 510 | fade:setFillColor( r,g,b ) 511 | effectView:insert(fade) 512 | -- 513 | showFx = transition.to ( fade, { alpha=1.0, time=fxTime } ) 514 | -- 515 | timer.performWithDelay( fxTime+safeDelay, fxEnded ) 516 | -- 517 | local function returnFade ( event ) 518 | 519 | showFx = transition.to ( fade, { alpha=0, time=fxTime } ) 520 | -- 521 | local function removeFade ( event ) 522 | fade:removeSelf() 523 | end 524 | -- 525 | timer.performWithDelay( fxTime+safeDelay, removeFade ) 526 | 527 | end 528 | -- 529 | timer.performWithDelay( fxTime+safeDelay+1, returnFade ) 530 | 531 | ----------------------------------- 532 | -- EFFECT: Flip 533 | ----------------------------------- 534 | 535 | elseif effect == "flip" then 536 | 537 | showFx = transition.to ( currView, { xScale=0.001, time=fxTime } ) 538 | showFx = transition.to ( currView, { x=display.contentWidth*0.5, time=fxTime } ) 539 | -- 540 | loadScene (newScene) 541 | -- 542 | nextView.xScale=0.001 543 | nextView.x=display.contentWidth*0.5 544 | -- 545 | showFx = transition.to ( nextView, { xScale=1, delay=fxTime, time=fxTime } ) 546 | showFx = transition.to ( nextView, { x=0, delay=fxTime, time=fxTime } ) 547 | -- 548 | timer.performWithDelay( fxTime*2+safeDelay, fxEnded ) 549 | 550 | ----------------------------------- 551 | -- EFFECT: Down Flip 552 | ----------------------------------- 553 | 554 | elseif effect == "downFlip" then 555 | 556 | showFx = transition.to ( currView, { xScale=0.7, time=fxTime } ) 557 | showFx = transition.to ( currView, { yScale=0.7, time=fxTime } ) 558 | showFx = transition.to ( currView, { x=display.contentWidth*0.15, time=fxTime } ) 559 | showFx = transition.to ( currView, { y=display.contentHeight*0.15, time=fxTime } ) 560 | showFx = transition.to ( currView, { xScale=0.001, delay=fxTime, time=fxTime } ) 561 | showFx = transition.to ( currView, { x=display.contentWidth*0.5, delay=fxTime, time=fxTime } ) 562 | -- 563 | loadScene (newScene) 564 | -- 565 | nextView.x = display.contentWidth*0.5 566 | nextView.xScale=0.001 567 | nextView.yScale=0.7 568 | nextView.y=display.contentHeight*0.15 569 | -- 570 | showFx = transition.to ( nextView, { x=display.contentWidth*0.15, delay=fxTime*2, time=fxTime } ) 571 | showFx = transition.to ( nextView, { xScale=0.7, delay=fxTime*2, time=fxTime } ) 572 | showFx = transition.to ( nextView, { xScale=1, delay=fxTime*3, time=fxTime } ) 573 | showFx = transition.to ( nextView, { yScale=1, delay=fxTime*3, time=fxTime } ) 574 | showFx = transition.to ( nextView, { x=0, delay=fxTime*3, time=fxTime } ) 575 | showFx = transition.to ( nextView, { y=0, delay=fxTime*3, time=fxTime } ) 576 | -- 577 | timer.performWithDelay( fxTime*4+safeDelay, fxEnded ) 578 | 579 | ----------------------------------- 580 | -- EFFECT: None 581 | ----------------------------------- 582 | 583 | else 584 | timer.performWithDelay( 0, fxEnded ) 585 | loadScene (newScene) 586 | end 587 | 588 | return true 589 | 590 | end -------------------------------------------------------------------------------- /src/CoronaDirectorExporter_newMerge.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License 3 | 4 | Copyright (c) 2011 Kevin C Jones aka @KevCJones aka him@kevincjones.co.uk 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | /* 26 | Corona Director Exporter 27 | ---------------------------------- 28 | 29 | Converts a layered PSD into a main.lua + and scenes along with an assets folder for all images used in the layout as seperate usable assets. 30 | I use templates in the script which are direct copies and make good use of the String.replace(what,with) js function. As we grow these $hooks 31 | to inject code can be easily exxpanded to support more and more complex jobs. The challenge will be finding nice ways to put them into the layers. 32 | 33 | Currently we make good use of keyterms in the name to help the exported identiy what to treat that layer as. These keyterms are removed once detected 34 | and not included in filenames and variable names for the objects they generate. e.g, myscene_scene strips _scene_ and calls the local scene file 'myscene.lua'. 35 | 36 | Keyterms: 37 | 38 | + _scene_ in layers on the root is the scene files themselves. 39 | + _button_ in group layers will beging creating a button in the scene and look inside the group for : 40 | - _default_ for the image used as the default state of the button (UI.lua) 41 | - _touch_ for the touch image. 42 | + _merge_ on groups will merge normal group layers into flat images and create single local variables to reference the image 43 | 44 | Note : If _touch_ or _default_ is the name of a group not a layer then that group is merged and saved as a single image as you would expect. 45 | 46 | Contributors 47 | ----------------- 48 | 49 | So far just me :) but I hope to involve everyone. These things tend to do the best when they have a following and people care about the code as well. I hope 50 | that we can keep it clean, readable and maintainable as we grow it, I will be adding it into Github sooner rather than later. With any luck the great guys at Corona 51 | will see fit to bundle it in the installer package and offer us all promotion codes for our efforts ;) ;) such rewards are merely a bonus... 52 | 53 | 54 | To Do: 55 | --------- 56 | 57 | - Add Sprite Sheet / MovieClip support 58 | - Add Basic Entry Animations (tweenfrombottom, top, left, right etc) 59 | 60 | 61 | Known Issues 62 | ------------------- 63 | 64 | - I added padding because in Corona i was seeing a glitch in the simulator for left hand edges which touched the screen. We should test with and without this on hardware to 65 | see if it is purely a scaling issue on the simulator or if there is an issue with the rendering, Padding is all sides and will auto offset the X,Y coord by -padding, -padding to compensate 66 | the invisible bordering. 67 | 68 | */ 69 | 70 | var scriptversion = "0.0.392"; 71 | var dom = app.activeDocument; 72 | var origURL = (dom!=null)?dom.path + "/" + dom.name:""; 73 | app.activeDocument.rulerUnits = Units.PIXELS; 74 | app.preferences.rulerUnits = Units.PIXELS; 75 | var totalLayers = dom.layers.length; 76 | var width = app.activeDocument.width.as('px'); 77 | var height = app.activeDocument.height.as('px'); 78 | var imagePadding = 1.0; //px 79 | var imagePaddingx2 = imagePadding*2; //px 80 | var nativePPI = Math.round(dom.resolution); 81 | 82 | //folder names 83 | var exportFolder = "export/" 84 | var assetsFolder = "images/"; 85 | 86 | //groups using the word _scene_ on the root layer are treated as such 87 | var groupStack = ["localGroup"]; 88 | var currentScene = null; 89 | var firstScene = ""; 90 | 91 | //file and code strings 92 | var SceneGroupString = ""; 93 | var SceneImagesString = ""; 94 | var sceneInsertsString = ""; 95 | var scenePositionsString = ""; 96 | var touchFunctionsString = ""; 97 | var listenerFunctionsString = ""; 98 | var configLua = ""; 99 | var mainLuaText = mainLuaTemplate(); 100 | var currentSceneText = ""; 101 | 102 | //exported png file names used to avoid conflicts 103 | var exportedPNGS = []; 104 | var closeList = [dom]; 105 | 106 | 107 | 108 | 109 | //Testing purposes only - in the event of a crash the following are suspected choke points 110 | //turn them off and back on with a test for each to see when the crash occurs.. 111 | 112 | var renderImages = true; 113 | var performUndos = true; 114 | var closeDocuments = true; 115 | 116 | //============================================================================================================== 117 | // CORE LOOP AND CODE GENERATION 118 | //============================================================================================================== 119 | 120 | 121 | try 122 | { 123 | 124 | trace("Starting the export using version "+scriptversion); 125 | 126 | trace("Purging Cache from Photoshop"); 127 | app.purge(PurgeTarget.ALLCACHES); 128 | 129 | //build scenes one group at a time 130 | for(i=0;i 0) 353 | { 354 | if(touchImageName.length == 0) 355 | touchImageName=defaultImageName; 356 | 357 | trace("--Generate button code"); 358 | 359 | //create button 360 | sceneInsertsString += generateInsertString(getCurrentGroupName(),groupName); 361 | SceneImagesString += generateUIButtonString(scenegroup,groupName,defaultImageName,touchImageName); 362 | scenePositionsString += generatePositionsString(scenegroup,groupName); 363 | } 364 | } 365 | 366 | function HandleMergeSceneGroup(scenegroup) 367 | { 368 | var isMerged = scenegroup.name.lastIndexOf ("_merge_"); 369 | var groupName = printUniquePNGName(scenegroup.name.substr(0,isMerged)); 370 | printAssetPath("MERGEDGROUP ",groupName+".png"); 371 | 372 | scenegroup.name = groupName+"_merge_"; 373 | 374 | scenePositionsString += generatePositionsString(scenegroup,groupName); 375 | SceneImagesString += generateNewImageString(groupName,scenegroup); 376 | 377 | 378 | saveLayerAsImage(scenegroup,groupName); 379 | 380 | trace("--Generate inser code"); 381 | 382 | sceneInsertsString += generateInsertString(getCurrentGroupName(),groupName); 383 | 384 | } 385 | 386 | function HandleSubGroup(scenegroup) 387 | { 388 | var newGroupName = sanitiseString(scenegroup.name); 389 | sceneInsertsString += generateInsertString(getCurrentGroupName(),newGroupName); 390 | groupStack.push(newGroupName); 391 | 392 | trace("SUBGROUP INSERTED"+newGroupName); 393 | 394 | SceneGroupString += generateNewGroupString(newGroupName); 395 | 396 | HandleSceneGroupFolder(scenegroup); 397 | } 398 | 399 | 400 | 401 | //============================================================================================================== 402 | // SUB STRING GENERATION FACTORIES - STACKED AND THEN SUBBED INTO FILE TEMPLATES 403 | //============================================================================================================== 404 | function generateNewGroupString(groupName) 405 | { 406 | return "local "+groupName+" = display.newGroup()\n"; 407 | } 408 | 409 | function generateNewImageString(filename,sceneObj) 410 | { 411 | var elWidth = getObjectWidth(sceneObj); 412 | var elHeight = getObjectHeight(sceneObj); 413 | 414 | elWidth = Math.min(elWidth,width+imagePaddingx2); 415 | elHeight= Math.min(elHeight,height+imagePaddingx2); 416 | elWidth= Math.max(elWidth,0); 417 | elHeight= Math.max(elHeight,0); 418 | 419 | return "local "+filename+" = display.newImageRect(\""+assetsFolder+filename+".png\","+elWidth+","+elHeight+");\n" 420 | } 421 | 422 | function generateListenerFunctionString(functionName) 423 | { 424 | return "\ 425 | local function "+functionName+" ( event )\ 426 | if event.phase == \"ended\" then\ 427 | --director:changeScene(\"scenename\",\"transitiontype\")\ 428 | print(\"touched "+functionName+"\")\ 429 | end\ 430 | end\n\n"; 431 | } 432 | 433 | function generatePositionsString(sceneObj,sceneObjName) 434 | { 435 | // Gets element position 436 | var elX = getObjectLeft(sceneObj); 437 | var elY = getObjectTop(sceneObj); 438 | 439 | elX = Math.min(elX,width); 440 | elY= Math.min(elY,height); 441 | elX = Math.max(elX,0-imagePadding); 442 | elY= Math.max(elY,0-imagePadding); 443 | 444 | var elWidth = getObjectWidth(sceneObj); 445 | var elHeight = getObjectHeight(sceneObj); 446 | 447 | elWidth = Math.min(elWidth,width+imagePaddingx2); 448 | elHeight= Math.min(elHeight,height+imagePaddingx2); 449 | elWidth= Math.max(elWidth,0); 450 | elHeight= Math.max(elHeight,0); 451 | 452 | var xMid = Math.floor(elX) + (Math.floor(elWidth)/2); 453 | var yMid = Math.floor(elY)+ (Math.floor(elHeight)/2); 454 | 455 | 456 | 457 | return "\ 458 | -------------- "+sceneObjName+".png\ 459 | "+sceneObjName+".x = "+Math.floor(xMid)+"\ 460 | "+sceneObjName+".y = "+Math.floor(yMid)+"\ 461 | -----------\ 462 | \n"; 463 | } 464 | 465 | function generateAddListener(objName,functionName) 466 | { 467 | return objName+":addEventListener( \"touch\" , "+functionName+" )\n"; 468 | } 469 | 470 | function generateUIButtonString(sceneObject,idName,defaultName,overName) 471 | { 472 | 473 | var defaultStr = assetsFolder+defaultName+".png"; 474 | var overStr = assetsFolder+overName+".png"; 475 | var touchFunctionName = "onTouch_"+idName; 476 | var elWidth = getObjectWidth(sceneObject); 477 | var elHeight = getObjectHeight(sceneObject); 478 | 479 | //create the listener function too since we have all the code we need for it 480 | touchFunctionsString += generateListenerFunctionString(touchFunctionName); 481 | listenerFunctionsString += generateAddListener(idName,touchFunctionName); 482 | 483 | return "\ 484 | --\ 485 | local "+idName+" = ui.newButton{\ 486 | defaultSrc = \""+defaultStr+"\",\ 487 | overSrc = \""+overStr+"\",\ 488 | defaultX = "+elWidth+",\ 489 | defaultY = "+elHeight+",\ 490 | onEvent = "+touchFunctionName+",\ 491 | overX = "+elWidth+",\ 492 | overY = "+elHeight+",\ 493 | id = \""+idName+"\"\ 494 | }\ 495 | --\n"; 496 | } 497 | 498 | //============================================================================================================== 499 | // FILE TEMPLATES FACTORIES director.lua and main.lua 500 | //============================================================================================================== 501 | 502 | //Main Lua when using Director class... 503 | //Need to replace $initScene with the first scene name 504 | function mainLuaTemplate() 505 | { 506 | 507 | return "\ 508 | display.setStatusBar( display.HiddenStatusBar )\ 509 | \ 510 | ---------------------------------------------------------------\ 511 | -- Import director class\ 512 | ---------------------------------------------------------------\ 513 | \ 514 | director = require(\"director\")\ 515 | \ 516 | ---------------------------------------------------------------\ 517 | -- Create a main group\ 518 | ---------------------------------------------------------------\ 519 | \ 520 | local mainGroup = display.newGroup()\ 521 | \ 522 | ---------------------------------------------------------------\ 523 | -- Main function\ 524 | ---------------------------------------------------------------\ 525 | \ 526 | local function main()\ 527 | \ 528 | -----------------------------------\ 529 | -- Add the group from director class\ 530 | -----------------------------------\ 531 | \ 532 | mainGroup:insert(director.directorView)\ 533 | \ 534 | -----------------------------------\ 535 | -- Change scene without effects\ 536 | -----------------------------------\ 537 | \ 538 | director:changeScene(\"$initScene\")\ 539 | \ 540 | -----------------------------------\ 541 | -- Return\ 542 | -----------------------------------\ 543 | \ 544 | return true\ 545 | end\ 546 | \ 547 | ---------------------------------------------------------------\ 548 | -- Begin\ 549 | ---------------------------------------------------------------\ 550 | \ 551 | main()\ 552 | \ 553 | -- It's that easy! :-)\ 554 | "; 555 | } 556 | 557 | //Scenes are morecomplicated 558 | //$groups -body text with all groups found in a scene created a ready to be added too. Some are added to eachother in the init 559 | //$width - width of the document 560 | //$height - height of the document 561 | //$displayObjects - all display obects found in scene- images buttons etc 562 | //$listeners - any button listeners - auto generated from buttons found. 563 | //$inserts - building a display heirachy of parent and children 564 | //$positions - positioning the assets 565 | //$addListeners - add listeners to buttons 566 | function sceneLuaTemplate() 567 | { 568 | return "\ 569 | \ 570 | module(..., package.seeall)\ 571 | \ 572 | ---------------------------------------------------------------\ 573 | -- IMPORTS\ 574 | ---------------------------------------------------------------\ 575 | \ 576 | local ui = require (\"ui\")\ 577 | \ 578 | ---------------------------------------------------------------\ 579 | -- GROUPS\ 580 | ---------------------------------------------------------------\ 581 | \ 582 | local localGroup = display.newGroup()\ 583 | $groups\ 584 | \ 585 | ---------------------------------------------------------------\ 586 | -- DISPLAY OBJECTS\ 587 | ---------------------------------------------------------------\ 588 | \ 589 | \ 590 | local background = display.newRect(0,0,$width,$height)\ 591 | $displayObjects\ 592 | \ 593 | ---------------------------------------------------------------\ 594 | -- LISTENERS\ 595 | ---------------------------------------------------------------\ 596 | \ 597 | $listeners\ 598 | \ 599 | ---------------------------------------------------------------\ 600 | -- INIT VARS\ 601 | ---------------------------------------------------------------\ 602 | \ 603 | local function initVars ()\ 604 | \ 605 | -----------------------------------\ 606 | -- Inserts\ 607 | -----------------------------------\ 608 | \ 609 | localGroup:insert(background)\ 610 | $inserts\ 611 | \ 612 | -----------------------------------\ 613 | -- Positions\ 614 | -----------------------------------\ 615 | \ 616 | $positions\ 617 | \ 618 | -----------------------------------\ 619 | -- Colors\ 620 | -----------------------------------\ 621 | \ 622 | background:setFillColor(0,0,0)\ 623 | \ 624 | -----------------------------------\ 625 | -- Listeners\ 626 | -----------------------------------\ 627 | \ 628 | $addListeners\ 629 | \ 630 | end\ 631 | \ 632 | ---------------------------------------------------------------\ 633 | -- CLEAN\ 634 | ---------------------------------------------------------------\ 635 | \ 636 | function clean ( event )\ 637 | print(\"cleaned\")\ 638 | end\ 639 | \ 640 | ---------------------------------------------------------------\ 641 | -- NEW\ 642 | ---------------------------------------------------------------\ 643 | \ 644 | function new()\ 645 | \ 646 | -----------------------------------\ 647 | -- Initiate variables\ 648 | -----------------------------------\ 649 | \ 650 | initVars()\ 651 | \ 652 | -----------------------------------\ 653 | -- MUST return a display.newGroup()\ 654 | -----------------------------------\ 655 | \ 656 | return localGroup\ 657 | \ 658 | end\ 659 | \ 660 | \ 661 | "; 662 | } 663 | 664 | 665 | function generateConfigLUAString(w,h) 666 | { 667 | return "\ 668 | application = \ 669 | {\ 670 | content =\ 671 | {\ 672 | width = "+w+",\ 673 | height ="+h+",\ 674 | scale = \"zoomStretch\",\ 675 | fps = 60\ 676 | },\ 677 | }\ 678 | "; 679 | } 680 | 681 | 682 | //============================================================================================================== 683 | //HELPER FUNCTIONS 684 | //============================================================================================================== 685 | //trace like as3 686 | function trace(text){$.writeln(text);}//for familiarity sake 687 | 688 | //the assets display name 689 | function printAssetPath(functionname,name) 690 | { 691 | var groupString = ""; 692 | for(j=1;j"; 694 | trace(functionname+":"+currentScene+"->"+groupString+name); 695 | } 696 | 697 | //should be expanded if we find other characters that balls up the LUA naming...I just picked any that came to mind. 698 | //a better way is to create a regexp but I find that for now we should leave it open and readable for the average joe. 699 | function sanitiseString(string) 700 | { 701 | string = string.replace ("(",""); 702 | string = string.replace (")",""); 703 | string = string.replace ("@",""); 704 | string = string.replace ("!",""); 705 | string = string.replace ("+",""); 706 | string = string.replace ("-",""); 707 | string = string.replace ("\\",""); 708 | string = string.replace ("/",""); 709 | string = string.replace ("[",""); 710 | string = string.replace ("]",""); 711 | string = string.replace (" ",""); 712 | string = string.replace (";",""); 713 | string = string.replace ("|",""); 714 | string = string.replace ("\"",""); 715 | string = string.replace ("'",""); 716 | string = string.replace ("£",""); 717 | string = string.replace ("$",""); 718 | string = string.replace ("%",""); 719 | string = string.replace ("^",""); 720 | string = string.replace ("&",""); 721 | string = string.replace ("*",""); 722 | string = string.replace ("`",""); 723 | string = string.replace ("#",""); 724 | string = string.replace ("<",""); 725 | string = string.replace (">",""); 726 | string = string.replace (" ",""); 727 | return string; 728 | } 729 | 730 | //generates a filename for PNG/Layername name, remembers the names and recurses with an incremented name to 731 | //avoid duplicates 732 | function printUniquePNGName(name,increment) 733 | { 734 | if(increment == null) increment = 0; 735 | var outName = name + ((increment>0)?"_"+increment+"_":""); 736 | 737 | //could use a reg exp for this but this is more like english for others to edit... 738 | outName = sanitiseString(outName); 739 | 740 | var allNames = exportedPNGS.join ("@"); 741 | if(allNames.lastIndexOf (outName) == -1) 742 | { 743 | exportedPNGS.push (outName) 744 | return outName; 745 | } 746 | else 747 | { 748 | increment += 1; 749 | trace(increment); 750 | return printUniquePNGName(name,increment); 751 | } 752 | } 753 | 754 | 755 | 756 | //save a textfile 757 | function saveFile(fileName,fileContents) 758 | { 759 | // Save main.lua 760 | // Verifies which kind of line feed 761 | if ($.os.search(/windows/i) != -1) { 762 | fileLineFeed = "Windows" 763 | } else { 764 | fileLineFeed = "Macintosh" 765 | } 766 | dire = dom.path //current application folder 767 | 768 | fileOut = new File(dire+"/"+exportFolder+fileName) 769 | fileOut.lineFeed = fileLineFeed 770 | fileOut.open("w", "TEXT", "????") 771 | fileOut.write(fileContents) 772 | fileOut.close() 773 | trace("Your file was saved at "+dire+"/"+exportFolder+fileName); 774 | } 775 | 776 | //helper to get the last name in the stack 777 | function getCurrentGroupName() 778 | { 779 | return groupStack[groupStack.length-1]; 780 | } 781 | 782 | //trace helper - see console outputs 783 | function generateInsertString(groupName,insert) 784 | { 785 | return groupName+":insert("+insert+")\n\t"; 786 | } 787 | 788 | //get object x 789 | function getObjectLeft(sceneObj) 790 | { 791 | return sceneObj.bounds[0].as("px") ; 792 | } 793 | 794 | //get object y 795 | function getObjectTop(sceneObj) 796 | { 797 | return sceneObj.bounds[1].as("px") ; 798 | } 799 | 800 | //get object width 801 | function getObjectWidth(sceneObj,nonPadded) 802 | { 803 | var paddedReq = (nonPadded != null); 804 | var elX = sceneObj.bounds[0].as("px"); 805 | var nonPaddedWidth = (sceneObj.bounds[2].as("px") - elX); 806 | 807 | if(paddedReq == true) return nonPaddedWidth; 808 | else return nonPaddedWidth+imagePaddingx2 809 | } 810 | 811 | //get height of an object 812 | function getObjectHeight(sceneObj,nonPadded) 813 | { 814 | var paddedReq = (nonPadded != null); 815 | var elY = sceneObj.bounds[1].as("px"); 816 | var nonPaddedHeight = sceneObj.bounds[3].as("px") - elY; 817 | 818 | if(nonPadded == true) return nonPaddedHeight; 819 | else return nonPaddedHeight+imagePaddingx2 820 | } 821 | 822 | //saves the layer as an image by calling my saved scripts 823 | function saveLayerAsImage(sceneObj,sceneObjName) 824 | { 825 | var elX = getObjectLeft(sceneObj); 826 | var elY = getObjectTop(sceneObj); 827 | 828 | //non padded height and width 829 | var elWidth = getObjectWidth(sceneObj,true); 830 | var elHeight = getObjectHeight(sceneObj,true); 831 | 832 | if((elWidth>0) && (elHeight>0)) 833 | { 834 | //layer UID - during a save the app selects a layer by name... this caused the error if you had duplicate layers because it stops on first find. 835 | //Solution assign a temp UID to the layer while saving and put it back afterwards... 836 | var oldLayerName = sceneObj.name; 837 | sceneObj.name= new Date().getTime(); 838 | trace("temp layer name is "+sceneObj.name); 839 | 840 | if(sceneObj.typename =="LayerSet") 841 | { 842 | sceneObj=sceneObj.merge(); 843 | //non padded height and width 844 | elWidth = getObjectWidth(sceneObj,true); 845 | elHeight = getObjectHeight(sceneObj,true); 846 | } 847 | 848 | elWidth = Math.min(elWidth,width); 849 | elHeight = Math.min(elHeight,height); 850 | 851 | savePNGLayer(sceneObj.name,elWidth,elHeight,nativePPI,dom.path+"/"+exportFolder+assetsFolder+sceneObjName+".png"); 852 | 853 | sceneObj.name = oldLayerName; 854 | trace("--Layer name restored back to " + oldLayerName); 855 | 856 | }else 857 | { 858 | trace("WARNING : CANNOT SAVE EMPTY LAYERS "+sceneObjName); 859 | } 860 | } 861 | 862 | 863 | //generated ussing scriptlistener plugin... fugly but this was a complicated step and this made it easier... 864 | //generated , tweaked and left 865 | //example call savePNGLayer("a_1_",292,569,72,dom.path+"/"+"autoLayerName.png"); 866 | function savePNGLayer(layerName,ww,hh,ppi,pngFilename) 867 | { 868 | if(!renderImages) return; 869 | 870 | var padding = imagePaddingx2; 871 | trace("-- Called savePNGLayer --"); 872 | trace("--Select the layer by name --"+layerName); 873 | // ======================================================= select what its already selected 874 | var id329 = charIDToTypeID( "slct" ); 875 | var desc53 = new ActionDescriptor(); 876 | var id330 = charIDToTypeID( "null" ); 877 | var ref20 = new ActionReference(); 878 | var id331 = charIDToTypeID( "Lyr " ); 879 | ref20.putName( id331, layerName ); 880 | desc53.putReference( id330, ref20 ); 881 | var id332 = charIDToTypeID( "MkVs" ); 882 | desc53.putBoolean( id332, false ); 883 | executeAction( id329, desc53, DialogModes.NO ); 884 | 885 | dom.selection.selectAll(); 886 | dom.selection.copy(); 887 | 888 | trace("--Creating a new document of width and height "+String(ww) + " " + String(hh)); 889 | // ======================================================= 890 | var id279 = charIDToTypeID( "Mk " ); 891 | var desc45 = new ActionDescriptor(); 892 | var id280 = charIDToTypeID( "Nw " ); 893 | var desc46 = new ActionDescriptor(); 894 | var id281 = charIDToTypeID( "Md " ); 895 | var id282 = charIDToTypeID( "RGBM" ); 896 | desc46.putClass( id281, id282 ); 897 | var id283 = charIDToTypeID( "Wdth" ); 898 | var id284 = charIDToTypeID( "#Rlt" ); 899 | desc46.putUnitDouble( id283, id284, ww ); 900 | var id285 = charIDToTypeID( "Hght" ); 901 | var id286 = charIDToTypeID( "#Rlt" ); 902 | desc46.putUnitDouble( id285, id286, hh); 903 | var id287 = charIDToTypeID( "Rslt" ); 904 | var id288 = charIDToTypeID( "#Rsl" ); 905 | desc46.putUnitDouble( id287, id288, ppi ); 906 | var id289 = stringIDToTypeID( "pixelScaleFactor" ); 907 | desc46.putDouble( id289, 1.000000 ); 908 | var id290 = charIDToTypeID( "Fl " ); 909 | var id291 = charIDToTypeID( "Fl " ); 910 | var id292 = charIDToTypeID( "Trns" ); 911 | desc46.putEnumerated( id290, id291, id292 ); 912 | var id293 = charIDToTypeID( "Dpth" ); 913 | desc46.putInteger( id293, 8 ); 914 | var id294 = stringIDToTypeID( "profile" ); 915 | desc46.putString( id294, "sRGB IEC61966-2.1" ); 916 | var id295 = charIDToTypeID( "Dcmn" ); 917 | desc45.putObject( id280, id295, desc46 ); 918 | executeAction( id279, desc45, DialogModes.NO ); 919 | 920 | trace("--Pasting the copied clipboard data--"); 921 | app.activeDocument.paste (); 922 | 923 | trace("--Resizing the canvas to add padding--"); 924 | app.activeDocument.resizeCanvas (ww+padding, hh+padding, AnchorPosition.MIDDLECENTER); 925 | 926 | trace("--Save the image as a PNG --"+pngFilename); 927 | // ======================================================= 928 | var id300 = charIDToTypeID( "save" ); 929 | var desc48 = new ActionDescriptor(); 930 | var id301 = charIDToTypeID( "As " ); 931 | var desc49 = new ActionDescriptor(); 932 | var id302 = charIDToTypeID( "PGIT" ); 933 | var id303 = charIDToTypeID( "PGIT" ); 934 | var id304 = charIDToTypeID( "PGIN" ); 935 | desc49.putEnumerated( id302, id303, id304 ); 936 | var id305 = charIDToTypeID( "PNGf" ); 937 | var id306 = charIDToTypeID( "PNGf" ); 938 | var id307 = charIDToTypeID( "PGAd" ); 939 | desc49.putEnumerated( id305, id306, id307 ); 940 | var id308 = charIDToTypeID( "PNGF" ); 941 | desc48.putObject( id301, id308, desc49 ); 942 | var id309 = charIDToTypeID( "In " ); 943 | desc48.putPath( id309, new File( pngFilename ) ); 944 | var id310 = charIDToTypeID( "Cpy " ); 945 | desc48.putBoolean( id310, true ); 946 | executeAction( id300, desc48, DialogModes.NO ); 947 | 948 | 949 | trace("--Add the file to the close list-- "); 950 | closeList.push(app.activeDocument); 951 | app.activeDocument = dom; 952 | trace("--Completed the adding to close list...next graphic go!--"); 953 | 954 | 955 | } 956 | 957 | --------------------------------------------------------------------------------