| OLD | NEW |
| (Empty) |
| 1 # Copyright 2009, Google Inc. | |
| 2 # All rights reserved. | |
| 3 # | |
| 4 # Redistribution and use in source and binary forms, with or without | |
| 5 # modification, are permitted provided that the following conditions are | |
| 6 # met: | |
| 7 # | |
| 8 # * Redistributions of source code must retain the above copyright | |
| 9 # notice, this list of conditions and the following disclaimer. | |
| 10 # * Redistributions in binary form must reproduce the above | |
| 11 # copyright notice, this list of conditions and the following disclaimer | |
| 12 # in the documentation and/or other materials provided with the | |
| 13 # distribution. | |
| 14 # * Neither the name of Google Inc. nor the names of its | |
| 15 # contributors may be used to endorse or promote products derived from | |
| 16 # this software without specific prior written permission. | |
| 17 # | |
| 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 | |
| 30 | |
| 31 import __builtin__ | |
| 32 import os.path | |
| 33 import re | |
| 34 Import('env') | |
| 35 | |
| 36 class Error(Exception): | |
| 37 pass | |
| 38 | |
| 39 samples_output_dir = env.Dir('$OBJ_ROOT/samples').abspath | |
| 40 samples_artifact_dir = env.Dir('$ARTIFACTS_DIR/samples').abspath | |
| 41 | |
| 42 copyright_header = """/* | |
| 43 * Copyright 2009, Google Inc. | |
| 44 * All rights reserved. | |
| 45 * | |
| 46 * Redistribution and use in source and binary forms, with or without | |
| 47 * modification, are permitted provided that the following conditions are | |
| 48 * met: | |
| 49 * | |
| 50 * * Redistributions of source code must retain the above copyright | |
| 51 * notice, this list of conditions and the following disclaimer. | |
| 52 * * Redistributions in binary form must reproduce the above | |
| 53 * copyright notice, this list of conditions and the following disclaimer | |
| 54 * in the documentation and/or other materials provided with the | |
| 55 * distribution. | |
| 56 * * Neither the name of Google Inc. nor the names of its | |
| 57 * contributors may be used to endorse or promote products derived from | |
| 58 * this software without specific prior written permission. | |
| 59 * | |
| 60 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 61 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 62 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 63 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 64 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 65 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 66 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 67 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 68 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 69 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 70 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 71 */ | |
| 72 """ | |
| 73 | |
| 74 def sample_emitter(env, target, source): | |
| 75 target.append(env.subst('${TARGET.base}.js', target=target, source=source)) | |
| 76 return (target, source) | |
| 77 | |
| 78 def sample_action(target, source, env): | |
| 79 content = source[0].get_contents() | |
| 80 regexp = re.compile(r'(.*)<script(\s+type="text/javascript")' + | |
| 81 r'(\s+charset="utf-8")?\s*>(.*)</script>(.*)', re.DOTALL) | |
| 82 m = regexp.match(content) | |
| 83 if not m: | |
| 84 raise Error('Regexp failed on input file %s' % source.abspath) | |
| 85 (html_start, type, charset, script, html_end) = m.groups() | |
| 86 if not type: | |
| 87 raise Error('Found a script that lacked the javascript tag!'); | |
| 88 if not charset: | |
| 89 charset = '' | |
| 90 | |
| 91 html_content = ( | |
| 92 '%(html_start)s<script %(type)s%(charset)s ' | |
| 93 'src="%(js_path)s"></script>%(html_end)s' % | |
| 94 { | |
| 95 'html_start' : html_start, | |
| 96 'type' : type, | |
| 97 'charset' : charset, | |
| 98 'js_path' : target[1].name, | |
| 99 'html_end' : html_end | |
| 100 }) | |
| 101 | |
| 102 print "Writing sample HTML to %s" % target[0].abspath | |
| 103 file(target[0].abspath, 'wb').write(html_content) | |
| 104 print "Writing sample JS to %s" % target[1].abspath | |
| 105 file(target[1].abspath, 'wb').write(copyright_header + script) | |
| 106 return None | |
| 107 | |
| 108 sample_builder = Builder(action = sample_action, emitter = sample_emitter) | |
| 109 | |
| 110 env.Append(BUILDERS = {'SplitSampleHTML' : sample_builder}) | |
| 111 | |
| 112 # These are the files we process for the interactive sampler. | |
| 113 # TODO: We don't currently verify that these samples are included in | |
| 114 # interactive_samples.js, which constructs the sampler, or that all the files | |
| 115 # in there are mentioned here. The build script should parse the | |
| 116 # interactive_samples.js file instead of using this list. | |
| 117 samples = [ | |
| 118 '2d.html', | |
| 119 'animated-scene.html', | |
| 120 'animation.html', | |
| 121 'bitmap-draw-image.html', | |
| 122 'billboards.html', | |
| 123 'canvas-texturedraw.html', | |
| 124 'canvas.html', | |
| 125 'convolution.html', | |
| 126 'culling.html', | |
| 127 'customcamera.html', | |
| 128 'displayfps.html', | |
| 129 'error-texture.html', | |
| 130 'generate-texture.html', | |
| 131 'hellocube-colors.html', | |
| 132 'hellocube-textures.html', | |
| 133 'hellocube.html', | |
| 134 'helloworld.html', | |
| 135 'hud-2d-overlay.html', | |
| 136 'instance-override.html', | |
| 137 'instancing.html', | |
| 138 'juggler.html', | |
| 139 'julia.html', | |
| 140 'multiple-clients.html', | |
| 141 'multiple-views.html', | |
| 142 'old-school-shadows.html', | |
| 143 'particles.html', | |
| 144 'phongshading.html', | |
| 145 'picking.html', | |
| 146 'primitives.html', | |
| 147 'procedural-texture.html', | |
| 148 'render-mode.html', | |
| 149 'render-targets.html', | |
| 150 'rotatemodel.html', | |
| 151 'scatter-chart.html', | |
| 152 'shader-test.html', | |
| 153 'simple.html', | |
| 154 'simpletexture.html', | |
| 155 'skinning.html', | |
| 156 'sobel.html', | |
| 157 'stencil_example.html', | |
| 158 'texturesamplers.html', | |
| 159 'tutorial-primitive.html', | |
| 160 'vertex-shader.html', | |
| 161 'vertex-shader-animation.html', | |
| 162 'zsorting.html' | |
| 163 ] | |
| 164 | |
| 165 # Split the samples into separate HTML and JS files | |
| 166 for input_file in samples: | |
| 167 destdir = os.path.join(samples_artifact_dir, os.path.dirname(input_file)) | |
| 168 # env.SplitSampleHTML(os.path.join(destdir, 'sampler_' + input_file), | |
| 169 # input_file) | |
| 170 | |
| 171 # We want all the samples unprocessed, as well. | |
| 172 env.Replicate(destdir, input_file) | |
| 173 | |
| 174 env.Alias('samples_export', samples_artifact_dir) | |
| 175 | |
| 176 ###################################################################### | |
| 177 # | |
| 178 # PLEASE NOTE: If you add samples you MUST add their files to the | |
| 179 # MANIFEST file in this directory for them to be included in the docs. | |
| 180 # | |
| 181 ###################################################################### | |
| 182 | |
| 183 # Here we load up the manifest so that we only include the files that | |
| 184 # are part of the samples, and not any spurious test files or images | |
| 185 # that might be left around. | |
| 186 manifest = env.File("MANIFEST").get_contents().strip().split('\n') | |
| 187 manifest = [x.strip() for x in manifest] | |
| 188 | |
| 189 def DeferManifestInstall(env): | |
| 190 # Only do this if we tried to convert at least some samples (which | |
| 191 # means that at least some existed when we declared their build steps). | |
| 192 if len(env.GetPublished('samples', 'asset_files')) > 0: | |
| 193 for manifest_item in manifest: | |
| 194 # TODO: Why doesn't replicate hookup things correctly? | |
| 195 env.Command('$ARTIFACTS_DIR/samples/' + manifest_item, | |
| 196 '$MAIN_DIR/samples/' + manifest_item, | |
| 197 [Delete('$TARGET'), | |
| 198 Copy('$TARGET', '$SOURCE'), | |
| 199 Chmod('$TARGET', 0777)]) | |
| 200 | |
| 201 env.Defer(DeferManifestInstall) | |
| 202 | |
| 203 ####### | |
| 204 # Build JSON sample assets from zipped Collada files. Put them in the assets | |
| 205 # directory in the source tree (so that we can run the samples from the source | |
| 206 # tree). If one is needed in the scons-out artifacts directory, that's handled | |
| 207 # by the MANIFEST file. | |
| 208 | |
| 209 if env.Bit('mac'): | |
| 210 converter_path = env.subst('$ARTIFACTS_DIR/converter/o3dConverter$PROGSUFFIX') | |
| 211 else: | |
| 212 converter_path = env.subst('$ARTIFACTS_DIR/o3dConverter$PROGSUFFIX') | |
| 213 serializer_version_path = env.subst( | |
| 214 '$SCONSTRUCT_DIR/serializer/cross/version.h') | |
| 215 | |
| 216 def model_emitter(env, target, source): | |
| 217 # Massage the target a little bit. | |
| 218 sample_file = env.subst('${TARGET.srcdir}/${TARGET.filebase}.o3dtgz', | |
| 219 target=target, source=source) | |
| 220 sample_file = sample_file.replace('convert_','') | |
| 221 target = [env.File(sample_file)] | |
| 222 source.append(serializer_version_path) | |
| 223 source.append(converter_path) | |
| 224 return (target, source) | |
| 225 | |
| 226 def model_action(target, source, env): | |
| 227 import shutil | |
| 228 import subprocess | |
| 229 import stat | |
| 230 | |
| 231 # Invoke converter to generate target. | |
| 232 error = subprocess.call([ | |
| 233 converter_path, | |
| 234 '--no-condition', | |
| 235 '--up-axis=%s' % env['UP_AXIS'], | |
| 236 source[0].abspath, | |
| 237 target[0].abspath, | |
| 238 ], env={'LD_LIBRARY_PATH': env.Dir('$ARTIFACTS_DIR').abspath}) | |
| 239 if error != 0: | |
| 240 raise Exception('Failed to run o3dConverter on %s to produce %s' % | |
| 241 (source[0].abspath, target[0].abspath)) | |
| 242 | |
| 243 # Copy generated target to remaining targets. This should be faster than | |
| 244 # running the converter several times. | |
| 245 for item in target[1:]: | |
| 246 shutil.copy(target[0].abspath, item.abspath) | |
| 247 os.chmod(item.abspath, stat.S_IWRITE | stat.S_IREAD) | |
| 248 | |
| 249 model_builder = Builder(action = model_action, emitter = model_emitter) | |
| 250 | |
| 251 env.Append(BUILDERS = {'ConvertJsonSampleAssets' : model_builder}) | |
| 252 | |
| 253 x_up_env = env.Clone(UP_AXIS='1,0,0') | |
| 254 y_up_env = env.Clone(UP_AXIS='0,1,0') | |
| 255 z_up_env = env.Clone(UP_AXIS='0,0,1') | |
| 256 | |
| 257 models = [ | |
| 258 {'path': 'beachdemo/convert_assets/beachdemo.zip', 'env': z_up_env}, | |
| 259 {'path': 'beachdemo/convert_assets/beach-low-poly.dae', 'env': z_up_env}, | |
| 260 {'path': 'GoogleIO-2009/convert_assets/background.zip', 'env': y_up_env}, | |
| 261 {'path': 'GoogleIO-2009/convert_assets/character.zip', 'env': y_up_env}, | |
| 262 | |
| 263 {'path': 'home-configurators/convert_cbassets/House_Roofless.kmz', | |
| 264 'env': z_up_env}, | |
| 265 {'path': 'home-configurators/convert_cbassets/Agra_Rug.kmz', 'env': z_up_env}, | |
| 266 {'path': 'home-configurators/convert_cbassets/Asimi_Rug.kmz', 'env': z_up_env}
, | |
| 267 {'path': 'home-configurators/convert_cbassets/Camden_Chair.kmz', | |
| 268 'env': z_up_env}, | |
| 269 {'path': 'home-configurators/convert_cbassets/Elements_Bookshelf.kmz', | |
| 270 'env': z_up_env}, | |
| 271 {'path': 'home-configurators/convert_cbassets/Ferrara_Rug.kmz', | |
| 272 'env': z_up_env}, | |
| 273 {'path': 'home-configurators/convert_cbassets/Lounge_Chair.kmz', | |
| 274 'env': z_up_env}, | |
| 275 {'path': 'home-configurators/convert_cbassets/Lounge_Chaise.kmz', | |
| 276 'env': z_up_env}, | |
| 277 {'path': 'home-configurators/convert_cbassets/Lounge_Sofa.kmz', | |
| 278 'env': z_up_env}, | |
| 279 {'path': 'home-configurators/convert_cbassets/Lounge_Storage_Ottoman.kmz', | |
| 280 'env': z_up_env}, | |
| 281 {'path': 'home-configurators/convert_cbassets/Madison_Dining_Table.kmz', | |
| 282 'env': z_up_env}, | |
| 283 {'path': 'home-configurators/convert_cbassets/Miles_Side_Chair.kmz', | |
| 284 'env': z_up_env}, | |
| 285 {'path': 'home-configurators/convert_cbassets/Pullman_Bar_Stool.kmz', | |
| 286 'env': z_up_env}, | |
| 287 {'path': 'home-configurators/convert_cbassets/Puzzle_TV_Stand.kmz', | |
| 288 'env': z_up_env}, | |
| 289 {'path': 'home-configurators/convert_cbassets/Stow_Leather_Ottoman.kmz', | |
| 290 'env': z_up_env}, | |
| 291 {'path': 'home-configurators/convert_cbassets/Tivoli_Dining_Table.kmz', | |
| 292 'env': z_up_env}, | |
| 293 {'path': 'home-configurators/convert_cbassets/Tivoli_Miles_Dining_Set.kmz', | |
| 294 'env': z_up_env}, | |
| 295 {'path': 'home-configurators/convert_cbassets/Troy_Chair.kmz', | |
| 296 'env': z_up_env}, | |
| 297 {'path': 'home-configurators/convert_cbassets/Troy_Ottoman.kmz', | |
| 298 'env': z_up_env}, | |
| 299 {'path': 'home-configurators/convert_cbassets/Troy_Sofa.kmz', | |
| 300 'env': z_up_env}, | |
| 301 {'path': 'home-configurators/convert_cbassets/Troy_Storage_Ottoman.kmz', | |
| 302 'env': z_up_env}, | |
| 303 {'path': 'home-configurators/convert_cbassets/Troy_Twin_Sleeper.kmz', | |
| 304 'env': z_up_env}, | |
| 305 | |
| 306 | |
| 307 {'path': 'io/convert_levels/all_actors.kmz', 'env': y_up_env}, | |
| 308 {'path': 'io/convert_levels/map1.kmz', 'env': y_up_env}, | |
| 309 | |
| 310 {'path': 'simpleviewer/convert_assets/cube.zip', 'env': y_up_env}, | |
| 311 | |
| 312 {'path': 'convert_assets/dome1.zip', 'env': y_up_env}, | |
| 313 {'path': 'convert_assets/dome2.zip', 'env': y_up_env}, | |
| 314 {'path': 'convert_assets/dome3.zip', 'env': y_up_env}, | |
| 315 {'path': 'convert_assets/dome4.zip', 'env': y_up_env}, | |
| 316 {'path': 'convert_assets/kitty_151_idle_stand05_cff1.zip', 'env': y_up_env}, | |
| 317 {'path': 'convert_assets/part1.zip', 'env': y_up_env}, | |
| 318 {'path': 'convert_assets/part2.zip', 'env': y_up_env}, | |
| 319 {'path': 'convert_assets/part3.zip', 'env': y_up_env}, | |
| 320 {'path': 'convert_assets/seven_shapes.zip', 'env': y_up_env}, | |
| 321 {'path': 'convert_assets/stencil_frame.zip', 'env': y_up_env}, | |
| 322 {'path': 'convert_assets/teapot.zip', 'env': y_up_env}, | |
| 323 {'path': 'convert_assets/yard.zip', 'env': y_up_env}, | |
| 324 | |
| 325 {'path': 'waterdemo/convert_assets/bamboo.zip', 'env': y_up_env}, | |
| 326 {'path': 'waterdemo/convert_assets/coconuts.zip', 'env': y_up_env}, | |
| 327 {'path': 'waterdemo/convert_assets/driftwood.zip', 'env': y_up_env}, | |
| 328 {'path': 'waterdemo/convert_assets/island.zip', 'env': y_up_env}, | |
| 329 {'path': 'waterdemo/convert_assets/lazy_bridge.zip', 'env': y_up_env}, | |
| 330 {'path': 'waterdemo/convert_assets/palm_leaves.zip', 'env': y_up_env}, | |
| 331 {'path': 'waterdemo/convert_assets/palm_trees.zip', 'env': y_up_env}, | |
| 332 {'path': 'waterdemo/convert_assets/rocks.9.zip', 'env': y_up_env}, | |
| 333 {'path': 'waterdemo/convert_assets/rocks.zip', 'env': y_up_env}, | |
| 334 ] | |
| 335 | |
| 336 # Little dance to do this only once so MODE=all works. | |
| 337 try: | |
| 338 _ = __builtin__.done_json_assets | |
| 339 except AttributeError: | |
| 340 __builtin__.done_json_assets = True | |
| 341 for model in models: | |
| 342 # We generate the sample assets into the samples directory directly, | |
| 343 # and the artifacts directory in the name of sanity -- so we don't | |
| 344 # have to do a build whenever we change a .js file in order to test | |
| 345 # the change. We only generate them if the sources exist because we | |
| 346 # might not map them in all the time. | |
| 347 if os.path.exists( | |
| 348 model['env'].File("$SAMPLE_ASSETS/" + model['path']).abspath): | |
| 349 converted = model['env'].ConvertJsonSampleAssets( | |
| 350 source = "$SAMPLE_ASSETS/" + model['path'], | |
| 351 target = model['path']) | |
| 352 model['env'].Publish('samples', 'asset_files', converted); | |
| OLD | NEW |