Commit 633b6501 authored by Collin Jackson's avatar Collin Jackson

After running filter-branch, move root directory into sky/

parent 82404e03
.idea
.pub/
lib/_sdkext
packages
pubspec.lock
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//mojo/public/dart/rules.gni")
dart_pkg("sky") {
sources = [
"CHANGELOG.md",
"bin/init.dart",
"lib/animation/animated_simulation.dart",
"lib/animation/animation_performance.dart",
"lib/animation/curves.dart",
"lib/animation/scroll_behavior.dart",
"lib/animation/timeline.dart",
"lib/assets/.gitignore",
"lib/assets/material-design-icons.sha1",
"lib/base/debug.dart",
"lib/base/hit_test.dart",
"lib/base/lerp.dart",
"lib/base/node.dart",
"lib/base/scheduler.dart",
"lib/download_material_design_icons",
"lib/editing/editable_string.dart",
"lib/editing/editable_text.dart",
"lib/editing/input.dart",
"lib/mojo/activity.dart",
"lib/mojo/asset_bundle.dart",
"lib/mojo/embedder.dart",
"lib/mojo/keyboard.dart",
"lib/mojo/net/fetch.dart",
"lib/mojo/net/image_cache.dart",
"lib/mojo/shell.dart",
"lib/painting/box_painter.dart",
"lib/painting/shadows.dart",
"lib/painting/text_style.dart",
"lib/rendering/auto_layout.dart",
"lib/rendering/block.dart",
"lib/rendering/box.dart",
"lib/rendering/flex.dart",
"lib/rendering/object.dart",
"lib/rendering/paragraph.dart",
"lib/rendering/sky_binding.dart",
"lib/rendering/stack.dart",
"lib/sky_tool",
"lib/theme/colors.dart",
"lib/theme/shadows.dart",
"lib/theme/theme_data.dart",
"lib/theme/typography.dart",
"lib/theme/view_configuration.dart",
"lib/widgets/animated_component.dart",
"lib/widgets/animation_builder.dart",
"lib/widgets/basic.dart",
"lib/widgets/block_viewport.dart",
"lib/widgets/button_base.dart",
"lib/widgets/card.dart",
"lib/widgets/checkbox.dart",
"lib/widgets/default_text_style.dart",
"lib/widgets/dialog.dart",
"lib/widgets/dismissable.dart",
"lib/widgets/drawer.dart",
"lib/widgets/drawer_divider.dart",
"lib/widgets/drawer_header.dart",
"lib/widgets/drawer_item.dart",
"lib/widgets/fixed_height_scrollable.dart",
"lib/widgets/flat_button.dart",
"lib/widgets/floating_action_button.dart",
"lib/widgets/icon.dart",
"lib/widgets/icon_button.dart",
"lib/widgets/ink_well.dart",
"lib/widgets/material.dart",
"lib/widgets/material_button.dart",
"lib/widgets/modal_overlay.dart",
"lib/widgets/navigator.dart",
"lib/widgets/popup_menu.dart",
"lib/widgets/popup_menu_item.dart",
"lib/widgets/radio.dart",
"lib/widgets/raised_button.dart",
"lib/widgets/scaffold.dart",
"lib/widgets/scrollable.dart",
"lib/widgets/scrollable_list.dart",
"lib/widgets/scrollable_viewport.dart",
"lib/widgets/snack_bar.dart",
"lib/widgets/switch.dart",
"lib/widgets/tabs.dart",
"lib/widgets/task_description.dart",
"lib/widgets/theme.dart",
"lib/widgets/toggleable.dart",
"lib/widgets/tool_bar.dart",
"lib/widgets/variable_height_scrollable.dart",
"lib/widgets/widget.dart",
"pubspec.yaml",
]
# List of mojom targets that the sky pkg exports
deps = [
"//mojo/services/asset_bundle/public/interfaces",
"//mojo/services/keyboard/public/interfaces",
"//sky/services/activity:interfaces",
"//sky/services/engine:interfaces",
]
datadeps = [
"//mojo/dart/mojo_services",
"//mojo/dart/mojom",
"//mojo/public/dart:mojo",
"//sky/engine/bindings",
"//sky/services/testing:interfaces",
"//sky/services/media:interfaces",
"//third_party/dart-pkg",
]
sdk_ext_directory = "$root_gen_dir/sky/bindings"
sdk_ext_files = [
"//sky/engine/bindings/sky_internals.dart",
"//sky/engine/bindings/builtin_natives.dart",
]
sdk_ext_mappings = [
"dart:sky,dart_sky.dart",
"dart:sky.internals,sky_internals.dart",
"dart:sky_builtin_natvies,builtin_natives.dart",
]
}
action("material_design_icons") {
input_dir = "lib/assets/material-design-icons"
output_dir = "$root_gen_dir/dart-pkg/sky/lib/assets"
stamp = "$target_gen_dir/material_design_icons_linked"
sources = [
"lib/assets/material-design-icons.sha1",
]
outputs = [
stamp,
]
script = "//build/symlink.py"
args = [
"--force",
rebase_path(input_dir, output_dir),
rebase_path(output_dir, root_build_dir),
"--touch",
rebase_path(stamp, root_build_dir),
]
deps = [
":sky",
]
}
group("sdk") {
deps = [
":sky",
":material_design_icons",
]
}
## 0.0.18
- 41 changes: https://github.com/domokit/mojo/compare/246e279...c3119f6
## 0.0.17
- 18 changes: https://github.com/domokit/mojo/compare/e7433cf...8879bfd
## 0.0.16
- 27 changes: https://github.com/domokit/mojo/compare/e028733...e7433cf
## 0.0.15
- 6 changes: https://github.com/domokit/mojo/compare/4df2d39...e028733
## 0.0.14
- 42 changes: https://github.com/domokit/mojo/compare/3de9766...cf84c48
## 0.0.13
- 70 changes: https://github.com/domokit/mojo/compare/889091e...136e0d4
## 0.0.12
- 29 changes: https://github.com/domokit/mojo/compare/e25e3e2...432ce45
- Fixed sky_tool to work again.
## 0.0.11
- 197 changes: https://github.com/domokit/mojo/compare/bdbb0c7...fb1b726
## 0.0.10
- 23 changes: https://github.com/domokit/mojo/compare/1b7bcee...be9dad7
## 0.0.8
- Fix 2 crashes in SkyDemo.apk, updated widgets. 0.0.7 was skipped.
## 0.0.6
- First release after Dart summit. Adds new main.dart based workflow.
## 0.0.5+dart-summit-7
- Fix crash in sky_tool stop_tracing.
## 0.0.5+dart-summit-6
- Fix missing include in sky_tool causing failure.
## 0.0.5+dart-summit-5
- Added sky_tool start_tracing and stop_tracing.
## 0.0.5+dart-summit-4
- Added download_material_design_icons script.
## 0.0.5+dart-summit-3
- Fix typo in lib/sky_tool causing syntax error when run.
## 0.0.5+dart-summit-2
- Various demo fixes and added ChangeLogs.
## 0.0.5+dart-summit-1
- Branched from mojo trunk to stabalize for Dart summit.
## 0.0.2
- sdk_additions now includes previously missing imports.
- added lib/sky_tool, and supporting apks/SkyDemo.apk
Contributing
============
[sky_sdk](https://github.com/domokit/sky_sdk) is generated from the
[mojo repository](https://github.com/domokit/mojo) using
[deploy_sdk.py](https://github.com/domokit/mojo/blob/master/sky/tools/deploy_sdk.py)
Static files (including this README.md) are located under
[sky/sdk](https://github.com/domokit/mojo/tree/master/sky/sdk). Pull
requests and issue reports are glady accepted at the
[mojo repository](https://github.com/domokit/mojo)!
Sky
===
Sky is an experimental, high-performance UI framework for mobile apps. Sky helps
you create apps with beautiful user interfaces and high-quality interactive
design that run smoothly at 120 Hz.
Sky consists of two components:
1. *The Sky engine.* The engine is the core of the system. Written in C++, the
engine provides the muscle of the Sky system. The engine provides
several primitives, including a soft real-time scheduler and a hierarchical,
retained-mode graphics system, that let you build high-quality apps.
2. *The Sky framework.* The [framework](packages/sky/lib/framework) makes it
easy to build apps using Sky by providing familiar user interface widgets,
such as buttons, infinite lists, and animations, on top of the engine using
Dart. These extensible components follow a functional programming style
inspired by [React](http://facebook.github.io/react/).
We're still iterating on Sky heavily, which means the framework and underlying
engine are both likely to change in incompatible ways several times, but if
you're interested in trying out the system, this document can help you get
started.
Examples
--------
Sky uses Dart and Sky applications are
[Dart Packages](https://www.dartlang.org/docs/tutorials/shared-pkgs/).
Application creation starts by creating a new directory and
adding a [pubspec.yaml](https://www.dartlang.org/tools/pub/pubspec.html):
pubspec.yaml for your app:
```yaml
name: your_app_name
dependencies:
sky: any
```
Once the pubspec is in place, create a `lib` directory (where your dart code
will go), ensure that the 'dart' and 'pub' executables are on your $PATH and
run the following:
`pub get && pub run sky:init`.
Currently the Sky Engine assumes the entry point for your application is a
`main` function in a Dart file inside your package:
```dart
import 'package:sky/widgets/basic.dart';
class HelloWorldApp extends App {
Widget build() {
return new Text('Hello, world!');
}
}
void main() {
runApp(new HelloWorldApp());
}
```
Execution starts in `main`, which instructs the framework to run a new
instance of the `HelloWorldApp`. The framework then calls the `build()`
function on `HelloWorldApp` to create a tree of widgets, some of which might
be other `Components`, which in turn have `build()` functions that generate
more widgets iteratively to create the widget hierarchy.
Later, if a `Component` changes state, the framework calls that component's
`build()` function again to create a new widget tree. The framework diffs the
new widget tree against the old widget tree and any differences are applyed
to the underlying render tree.
* To learn more about the widget system, please see the
[widgets tutorial](lib/widgets/README.md).
* To learn how to run Sky on your device, please see the
[Running a Sky application](#running-a-sky-application) section in this
document.
* To dive into examples, please see the [examples directory](example/).
Services
--------
Sky apps can access services from the host operating system using Mojo IPC. For
example, you can access the network using the `network_service.mojom` interface.
Although you can use these low-level interfaces directly, you might prefer to
access these services via libraries in the framework. For example, the
`fetch.dart` library wraps the underlying `network_service.mojom` in an
ergonomic interface:
```dart
import 'package:sky/mojo/net/fetch.dart';
main() async {
Response response = await fetchBody('example.txt');
print(response.bodyAsString());
}
```
Set up your computer
--------------------
1. Install the Dart SDK:
- https://www.dartlang.org/tools/download.html
2. Install the `adb` tool from the Android SDK:
- https://developer.android.com/sdk/installing/index.html
3. Install the Sky SDK:
- `git clone https://github.com/domokit/sky_sdk.git`
4. Ensure that `$DART_SDK` is set to the path of your Dart SDK and `adb`
(inside `platform-tools` in the android sdk) is in your `$PATH`.
Set up your device
------------------
Currently Sky requires an Android device running the Lollipop (or newer) version
of the Android operating system.
1. Enable developer mode on your device by visiting `Settings > About phone`
and tapping the `Build number` field five times.
2. Enable `USB debugging` in `Settings > Developer options`.
3. Using a USB cable, plug your phone into your computer. If prompted on your
device, authorize your computer to access your device.
Running a Sky application
-------------------------
The `sky` pub package includes a `sky_tool` script to assist in running
Sky applications inside the `SkyDemo.apk` harness. The `sky_tool` script
expects to be run from the root directory of your application pub package. To
run one of the examples in this SDK, try:
1. `cd example/stocks`
2. `pub get` to set up a copy of the sky package in the app directory.
3. `./packages/sky/sky_tool start` to start the dev server and upload your
app to the device.
(NOTE: add a `--install` flag to install `SkyDemo.apk` if it is not already
installed on the device.)
4. Use `adb logcat` to view any errors or Dart `print()` output from the app.
`adb logcat -s chromium` can be used to filter only adb messages from
`SkyDemo.apk` (which for
[legacy reasons](https://github.com/domokit/mojo/issues/129) still uses the
android log tag `chromium`).
Measuring Performance
---------------------
Sky has support for generating trace files compatible with
[Chrome's about:tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool).
`packages/sky/sky_tool start_tracing` and `packages/sky/sky_tool stop_tracing`
are the commands to use.
Due to https://github.com/domokit/mojo/issues/127 tracing currently
requires root access on the device.
Debugging
---------
Sky uses [Observatory](https://www.dartlang.org/tools/observatory/) for
debugging and profiling. While running your Sky app using `sky_tool`, you can
access Observatory by navigating your web browser to http://localhost:8181/.
Building a standalone MyApp
---------------------------
Although it is possible to bundle the Sky Engine in your own app (instead of
running your code inside SkyDemo.apk), right now doing so is difficult.
There is one example of doing so if you're feeling brave:
https://github.com/domokit/mojo/tree/master/sky/sdk/example/stocks
Eventually we plan to make this much easier and support platforms other than
Android, but that work is yet in progress.
Adding Services to MyApp
------------------------
[Mojo IPC](https://github.com/domokit/mojo) is an inter-process-communication
system designed to provide cross-thread, cross-process, and language-agnostic
communication between applications. Sky uses Mojo IPC to make it possible
to write UI code in Dart and yet depend on networking code, etc. written in
another language. Services are replicable, meaning that Dart code
written to use the `network_service` remains portable to any platform
(iOS, Android, etc.) by simply providing a 'natively' written `network_service`.
Embedders of the Sky Engine and consumers of the Sky Framework can use this
same mechanism to expose not only existing services like the
[Keyboard](https://github.com/domokit/mojo/blob/master/mojo/services/keyboard/public/interfaces/keyboard.mojom)
service to allow Sky Framework Dart code to interface with the underlying
platform's Keyboard, but also to expose any additional non-Dart business logic
to Sky/Dart UI code.
As an example, [SkyApplication](https://github.com/domokit/mojo/blob/master/sky/shell/org/domokit/sky/shell/SkyApplication.java)
exposes a mojo `network_service` (required by Sky Engine C++ code)
[SkyDemoApplication](https://github.com/domokit/mojo/blob/master/sky/apk/demo/org/domokit/sky/demo/SkyDemoApplication.java)
additionally exposes `keyboard_service` and `sensor_service` for use by the Sky
Framework from Dart.
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/*
* This script should be invoked via 'pub run' after 'pub get':
* $ pub run sky:init
* NOTE: The 'dart' executable must be on your $PATH for this script to work.
*/
import 'dart:io';
main(List<String> arguments) {
ProcessResult result = Process.runSync('dart', ['-p', 'packages', 'packages/mojom/generate.dart']);
stdout.write(result.stdout);
stderr.write(result.stderr);
}
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
group("example") {
testonly = true
deps = [
"//sky/sdk/example/demo_launcher",
"//sky/sdk/example/game",
"//sky/sdk/example/mine_digger",
"//sky/sdk/example/rendering",
"//sky/sdk/example/stocks",
"//sky/sdk/example/widgets",
]
}
Sky Examples
============
This directory contains several examples of using Sky. Each of these is an
individual Dart application package. If you wish to run them with `sky_tool`
then you will want to run `pub get` inside their directory before running
`./packages/sky/sky_tool start`.
1. *Hello, world.* The [hello world app](hello_world) is a basic app that shows
the text "hello, world."
2. *Stocks.* The [stocks app](stocks) is an example of a typical mobile app
built using Sky. The app shows a list of all the stocks in the NASDAQ.
3. *Widgets.* The [widgets app](widgets) contains a number of Sky widgets so
you can experiment with them in a simple container.
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/theme/typography.dart' as typography;
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/default_text_style.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/widget.dart';
import 'package:sky/widgets/task_description.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'package:sky/widgets/icon_button.dart';
import 'package:sky/widgets/floating_action_button.dart';
import 'package:sky/widgets/icon.dart';
import 'package:sky/widgets/material.dart';
import 'package:sky/editing/input.dart';
import 'package:sky/widgets/scrollable_viewport.dart';
class Field extends Component {
Field({this.icon: null, this.placeholder: null});
String icon;
String placeholder;
Widget build() {
return new Flex([
new Padding(
padding: const EdgeDims.symmetric(horizontal: 16.0),
child: new Icon(type:icon, size:24)
),
new Flexible(child:new Input(placeholder:placeholder, focused:false))
],
direction: FlexDirection.horizontal
);
}
}
class AddressBookApp extends App {
Widget buildToolBar() {
return new ToolBar(
left: new IconButton(icon: "navigation/arrow_back"),
right: [new IconButton(icon: "navigation/check")]
);
}
Widget buildFloatingActionButton() {
return new FloatingActionButton(
child: new Icon(type: 'image/photo_camera', size: 24),
backgroundColor: Theme.of(this).accentColor
);
}
Widget buildBody() {
return new Material(
child: new ScrollableBlock([
new AspectRatio(
aspectRatio: 16.0 / 9.0,
child: new Container(
decoration: new BoxDecoration(backgroundColor: colors.Purple[300])
)
),
new Field(icon:"social/person", placeholder:"Name"),
new Field(icon: "communication/phone", placeholder:"Phone"),
new Field(icon: "communication/email", placeholder:"Email"),
new Field(icon: "maps/place", placeholder:"Address"),
new Field(icon: "av/volume_up", placeholder:"Ringtone"),
new Field(icon: "content/add", placeholder:"Add note"),
])
);
}
Widget buildMain() {
return new Scaffold(
toolbar: buildToolBar(),
body: buildBody(),
floatingActionButton: buildFloatingActionButton()
);
}
Widget build() {
ThemeData theme = new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: colors.Teal,
accentColor: colors.PinkAccent[100]
);
return new Theme(
data: theme,
child: new DefaultTextStyle(
style: typography.error, // if you see this, you've forgotten to correctly configure the text style!
child: new TaskDescription(
label: 'Address Book',
child: buildMain()
)
)
);
}
}
void main() {
runApp(new AddressBookApp());
}
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//sky/build/sky_app.gni")
sky_app("demo_launcher") {
main_dart = "lib/main.dart"
manifest = "sky.yaml"
if (is_android) {
apk_name = "SkyDemo"
bundles = [
"//sky/sdk/example/fitness",
"//sky/sdk/example/game",
"//sky/sdk/example/mine_digger",
"//sky/sdk/example/rendering:interactive_flex",
"//sky/sdk/example/stocks",
"//sky/sdk/example/widgets:cards",
]
deps = [
"//sky/sdk/example/demo_launcher/apk:java",
"//sky/sdk/example/demo_launcher/apk:resources",
]
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.domokit.sky.demo" android:versionCode="18" android:versionName="0.0.18">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
<application android:icon="@mipmap/ic_launcher" android:label="Sky" android:name="SkyDemoApplication">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:documentLaunchMode="always" android:hardwareAccelerated="true" android:launchMode="standard" android:name="SkyDemoActivity" android:theme="@android:style/Theme.Black.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
assert(is_android)
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
android_library("java") {
java_files = [
"org/domokit/sky/demo/SkyDemoActivity.java",
"org/domokit/sky/demo/SkyDemoApplication.java",
]
deps = [
"//base:base_java",
"//mojo/public/java:bindings",
"//mojo/public/java:system",
"//mojo/services/sensors/public/interfaces:interfaces_java",
"//services/sensors:sensors_lib",
"//sky/services/media:media_lib",
"//sky/services/media:interfaces_java",
"//sky/shell:java",
]
}
android_resources("resources") {
resource_dirs = [ "res" ]
android_manifest = "AndroidManifest.xml"
}
Icon image comes from:
https://openclipart.org/detail/30073/tango%20weather%20few%20clouds
and is public domain.
Icon resources were generated using:
http://romannurik.github.io/AndroidAssetStudio/icons-launcher.html
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.domokit.sky.demo;
import android.content.Intent;
import org.domokit.sky.shell.SkyActivity;
/**
* Main activity for SkyDemo.
*/
public class SkyDemoActivity extends SkyActivity {
@Override
protected void onSkyReady() {
Intent intent = getIntent();
String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
String bundleName = intent.getStringExtra("bundleName");
if (bundleName != null && loadBundleByName(bundleName)) {
return;
}
loadUrl(intent.getDataString());
return;
}
super.onSkyReady();
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.domokit.sky.demo;
import android.content.Context;
import org.chromium.mojo.sensors.SensorServiceImpl;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojom.media.MediaService;
import org.chromium.mojom.sensors.SensorService;
import org.domokit.media.MediaServiceImpl;
import org.domokit.sky.shell.ResourceExtractor;
import org.domokit.sky.shell.ServiceFactory;
import org.domokit.sky.shell.ServiceRegistry;
import org.domokit.sky.shell.SkyApplication;
/**
* SkyDemo implementation of {@link android.app.Application}
*/
public class SkyDemoApplication extends SkyApplication {
private static final String[] DEMO_RESOURCES = {
"cards.skyx",
"fitness.skyx",
"game.skyx",
"interactive_flex.skyx",
"mine_digger.skyx",
"stocks.skyx",
};
@Override
protected void onBeforeResourceExtraction(ResourceExtractor extractor) {
super.onBeforeResourceExtraction(extractor);
extractor.addResources(DEMO_RESOURCES);
}
@Override
public void onServiceRegistryAvailable(ServiceRegistry registry) {
super.onServiceRegistryAvailable(registry);
registry.register(SensorService.MANAGER.getName(), new ServiceFactory() {
@Override
public void connectToService(Context context, Core core, MessagePipeHandle pipe) {
SensorService.MANAGER.bind(new SensorServiceImpl(context), pipe);
}
});
registry.register(MediaService.MANAGER.getName(), new ServiceFactory() {
@Override
public void connectToService(Context context, Core core, MessagePipeHandle pipe) {
MediaService.MANAGER.bind(new MediaServiceImpl(context, core), pipe);
}
});
}
}
First version published to production from our service account.
\ No newline at end of file
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/mojo/activity.dart' as activity;
import 'package:sky/mojo/asset_bundle.dart';
import 'package:sky/painting/box_painter.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/theme/typography.dart' as typography;
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/card.dart';
import 'package:sky/widgets/material.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/task_description.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'package:sky/widgets/scrollable_list.dart';
import 'package:sky/widgets/ink_well.dart';
AssetBundle _initBundle() {
if (rootBundle != null)
return rootBundle;
const String _kAssetBase = '..';
return new NetworkAssetBundle(Uri.base.resolve(_kAssetBase));
}
final AssetBundle _bundle = _initBundle();
void launch(String relativeUrl, String bundle) {
// TODO(eseidel): This is a hack to keep non-skyx examples working for now:
Uri productionBase = Uri.parse(
'https://domokit.github.io/example/demo_launcher/lib/main.dart');
Uri base = rootBundle == null ? Uri.base : productionBase;
Uri url = base.resolve(relativeUrl);
activity.ComponentName component = new activity.ComponentName()
..packageName = 'org.domokit.sky.demo'
..className = 'org.domokit.sky.demo.SkyDemoActivity';
activity.Intent intent = new activity.Intent()
..action = 'android.intent.action.VIEW'
..component = component
..flags = activity.MULTIPLE_TASK | activity.NEW_DOCUMENT
..url = url.toString();
if (bundle != null) {
activity.StringExtra extra = new activity.StringExtra()
..name = 'bundleName'
..value = bundle;
intent.stringExtras = [extra];
}
activity.startActivity(intent);
}
class SkyDemo {
String name;
String href;
String bundle;
String description;
typography.TextTheme textTheme;
BoxDecoration decoration;
SkyDemo({ this.name, this.href, this.bundle, this.description, this.textTheme, this.decoration });
}
List<SkyDemo> demos = [
new SkyDemo(
name: 'Stocks',
href: '../../stocks/lib/main.dart',
bundle: 'stocks.skyx',
description: 'Multi-screen app with scrolling list',
textTheme: typography.black,
decoration: new BoxDecoration(
backgroundImage: new BackgroundImage(
image: _bundle.loadImage('assets/stocks_thumbnail.png'),
fit: BackgroundFit.cover
)
)
),
new SkyDemo(
name: 'Asteroids',
href: '../../game/main.dart',
bundle: 'game.skyx',
description: '2D game using sprite sheets to achieve high performance',
textTheme: typography.white,
decoration: new BoxDecoration(
backgroundImage: new BackgroundImage(
image: _bundle.loadImage('assets/game_thumbnail.png'),
fit: BackgroundFit.cover
)
)
),
new SkyDemo(
name: 'Fitness',
href: '../../fitness/lib/main.dart',
bundle: 'fitness.skyx',
description: 'Collin should write a nice description',
textTheme: typography.white,
decoration: new BoxDecoration(
backgroundColor: const Color(0xFF0081C6)
)
),
new SkyDemo(
name: 'Cards',
href: '../../widgets/card_collection.dart',
bundle: 'cards.skyx',
description: 'Demo of interactive Cards',
textTheme: typography.white,
decoration: new BoxDecoration(
backgroundColor: const Color(0xFF0081C6)
)
),
new SkyDemo(
name: 'Interactive Text',
href: '../../rendering/interactive_flex.dart',
bundle: 'interactive_flex.skyx',
description: 'Swipe to reflow the app',
textTheme: typography.white,
decoration: new BoxDecoration(
backgroundColor: const Color(0xFF0081C6)
)
),
// new SkyDemo(
// 'Touch Demo', '../../rendering/touch_demo.dart', 'Simple example showing handling of touch events at a low level'),
new SkyDemo(
name: 'Minedigger Game',
href: '../../mine_digger/lib/main.dart',
bundle: 'mine_digger.skyx',
description: 'Clone of the classic Minesweeper game',
textTheme: typography.white
),
// TODO(jackson): This doesn't seem to be working
// new SkyDemo('Licenses', 'LICENSES.sky'),
];
const double kCardHeight = 120.0;
const EdgeDims kListPadding = const EdgeDims.all(4.0);
class DemoList extends Component {
Widget buildCardContents(SkyDemo demo) {
return new Container(
decoration: demo.decoration,
child: new InkWell(
child: new Container(
margin: const EdgeDims.all(24.0),
child: new Flex([
new Text(demo.name, style: demo.textTheme.title),
new Flexible(
child: new Text(demo.description, style: demo.textTheme.subhead)
)
],
direction: FlexDirection.vertical,
alignItems: FlexAlignItems.start)
)
)
);
}
Widget buildDemo(SkyDemo demo) {
return new Listener(
key: demo.name,
onGestureTap: (_) => launch(demo.href, demo.bundle),
child: new Container(
height: kCardHeight,
child: new Card(
child: buildCardContents(demo)
)
)
);
}
Widget build() {
return new ScrollableList<SkyDemo>(
items: demos,
itemHeight: kCardHeight,
itemBuilder: buildDemo,
padding: kListPadding
);
}
}
class SkyHome extends App {
Widget build() {
return new Theme(
data: new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: colors.Teal
),
child: new TaskDescription(
label: 'Sky Demos',
child: new Scaffold(
toolbar: new ToolBar(center: new Text('Sky Demos')),
body: new Material(
type: MaterialType.canvas,
child: new DemoList()
)
)
)
);
}
}
void main() {
runApp(new SkyHome());
}
assets:
- assets/game_thumbnail.png
- assets/sector_thumbnail.png
- assets/stocks_thumbnail.png
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
assert(is_android)
import("//sky/build/sky_app.gni")
sky_app("fitness") {
apk_name = "Fitness"
main_dart = "lib/main.dart"
manifest = "sky.yaml"
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.domokit.fitness">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
<application android:name="org.domokit.sky.shell.SkyApplication" android:label="Fitness">
<activity android:name="org.domokit.sky.shell.SkyActivity"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
enum FitnessMode { measure, run }
enum BackupMode { enabled, disabled }
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/painting/text_style.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/drawer.dart';
import 'package:sky/widgets/drawer_divider.dart';
import 'package:sky/widgets/drawer_header.dart';
import 'package:sky/widgets/drawer_item.dart';
import 'package:sky/widgets/floating_action_button.dart';
import 'package:sky/widgets/icon_button.dart';
import 'package:sky/widgets/icon.dart';
import 'package:sky/widgets/material.dart';
import 'package:sky/widgets/navigator.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/snack_bar.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'package:sky/widgets/widget.dart';
import 'fitness_types.dart';
import 'measurement.dart';
class HomeFragment extends StatefulComponent {
HomeFragment(this.navigator, this.userData);
Navigator navigator;
List<Measurement> userData;
FitnessMode _fitnessMode = FitnessMode.measure;
void initState() {
// if (debug)
// new Timer(new Duration(seconds: 1), dumpState);
super.initState();
}
void syncFields(HomeFragment source) {
navigator = source.navigator;
userData = source.userData;
}
bool _isShowingSnackBar = false;
bool _isRunning = false;
void _handleFitnessModeChange(FitnessMode value) {
setState(() {
_fitnessMode = value;
});
}
Drawer buildDrawer() {
if (_drawerStatus == DrawerStatus.inactive)
return null;
return new Drawer(
showing: _drawerShowing,
level: 3,
onStatusChanged: _handleDrawerStatusChange,
navigator: navigator,
children: [
new DrawerHeader(children: [new Text('Fitness')]),
new DrawerItem(
icon: 'action/assessment',
onPressed: () => _handleFitnessModeChange(FitnessMode.measure),
selected: _fitnessMode == FitnessMode.measure,
children: [new Text('Measure')]),
new DrawerItem(
icon: 'maps/directions_run',
onPressed: () => _handleFitnessModeChange(FitnessMode.run),
selected: _fitnessMode == FitnessMode.run,
children: [new Text('Run')]),
new DrawerDivider(),
new DrawerItem(
icon: 'action/settings',
onPressed: _handleShowSettings,
children: [new Text('Settings')]),
new DrawerItem(
icon: 'action/help',
children: [new Text('Help & Feedback')])
]
);
}
bool _drawerShowing = false;
DrawerStatus _drawerStatus = DrawerStatus.inactive;
void _handleOpenDrawer() {
setState(() {
_drawerShowing = true;
_drawerStatus = DrawerStatus.active;
});
}
void _handleDrawerStatusChange(DrawerStatus status) {
setState(() {
_drawerStatus = status;
});
}
void _handleShowSettings() {
navigator.pop();
navigator.pushNamed('/settings');
}
// TODO(jackson): We should be localizing
String get fitnessModeTitle {
switch(_fitnessMode) {
case FitnessMode.measure: return "Measure";
case FitnessMode.run: return "Run";
}
}
Widget buildToolBar() {
return new ToolBar(
left: new IconButton(
icon: "navigation/menu",
onPressed: _handleOpenDrawer),
center: new Text(fitnessModeTitle)
);
}
Widget buildBody() {
TextStyle style = Theme.of(this).text.title;
switch (_fitnessMode) {
case FitnessMode.measure:
return new Material(
type: MaterialType.canvas,
child: new Flex(
[new Text("No measurements yet.\nAdd a new one!", style: style)],
justifyContent: FlexJustifyContent.center
)
);
case FitnessMode.run:
return new Material(
type: MaterialType.canvas,
child: new Flex([
new Text(_isRunning ? "Go go go!" : "Start a new run!", style: style)
], justifyContent: FlexJustifyContent.center)
);
}
}
void _handleUndo() {
setState(() {
_isShowingSnackBar = false;
});
}
Widget buildSnackBar() {
if (!_isShowingSnackBar)
return null;
return new SnackBar(
content: new Text("Measurement added!"),
actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)]
);
}
void _handleMeasurementAdded() {
setState(() {
_isShowingSnackBar = true;
});
}
void _handleRunStarted() {
setState(() {
_isRunning = true;
});
}
void _handleRunStopped() {
setState(() {
_isRunning = false;
});
}
Widget buildFloatingActionButton() {
switch (_fitnessMode) {
case FitnessMode.measure:
return new FloatingActionButton(
child: new Icon(type: 'content/add', size: 24),
onPressed: _handleMeasurementAdded
);
case FitnessMode.run:
return new FloatingActionButton(
child: new Icon(
type: _isRunning ? 'av/stop' : 'maps/directions_run',
size: 24
),
onPressed: _isRunning ? _handleRunStopped : _handleRunStarted
);
}
}
Widget build() {
return new Scaffold(
toolbar: buildToolBar(),
body: buildBody(),
snackBar: buildSnackBar(),
floatingActionButton: buildFloatingActionButton(),
drawer: buildDrawer()
);
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/navigator.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/widget.dart';
import 'package:sky/widgets/task_description.dart';
import 'measurement.dart';
import 'home.dart';
import 'settings.dart';
import 'fitness_types.dart';
class FitnessApp extends App {
NavigationState _navigationState;
void initState() {
_navigationState = new NavigationState([
new Route(
name: '/',
builder: (navigator, route) => new HomeFragment(navigator, _userData)
),
new Route(
name: '/settings',
builder: (navigator, route) => new SettingsFragment(navigator, backupSetting, settingsUpdater)
),
]);
super.initState();
}
void onBack() {
if (_navigationState.hasPrevious()) {
setState(() {
_navigationState.pop();
});
} else {
super.onBack();
}
}
BackupMode backupSetting = BackupMode.disabled;
void settingsUpdater({ BackupMode backup }) {
setState(() {
if (backup != null)
backupSetting = backup;
});
}
final List<Measurement> _userData = [
new Measurement(when: new DateTime.now(), weight: 400.0)
];
Widget build() {
return new Theme(
data: new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: colors.Indigo,
accentColor: colors.PinkAccent[200]
),
child: new TaskDescription(
label: 'Fitness',
child: new Navigator(_navigationState)
)
);
}
}
void main() {
runApp(new FitnessApp());
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
class Measurement {
final DateTime when;
final double weight;
Measurement({ this.when, this.weight });
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/drawer_item.dart';
import 'package:sky/widgets/switch.dart';
import 'package:sky/widgets/icon_button.dart';
import 'package:sky/widgets/material.dart';
import 'package:sky/widgets/navigator.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/scrollable_viewport.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'package:sky/widgets/theme.dart';
import 'fitness_types.dart';
typedef void SettingsUpdater({
BackupMode backup
});
class SettingsFragment extends Component {
SettingsFragment(this.navigator, this.backup, this.updater);
final Navigator navigator;
final BackupMode backup;
final SettingsUpdater updater;
bool showModeDialog = false;
void _handleBackupChanged(bool value) {
if (updater != null)
updater(backup: value ? BackupMode.enabled : BackupMode.disabled);
}
Widget buildToolBar() {
return new ToolBar(
left: new IconButton(
icon: "navigation/arrow_back",
onPressed: navigator.pop),
center: new Text('Settings')
);
}
Widget buildSettingsPane() {
return new Material(
type: MaterialType.canvas,
child: new ScrollableViewport(
child: new Container(
padding: const EdgeDims.symmetric(vertical: 20.0),
child: new Block([
new DrawerItem(
onPressed: () { _handleBackupChanged(!(backup == BackupMode.enabled)); },
children: [
new Flexible(child: new Text('Back up data to the cloud')),
new Switch(value: backup == BackupMode.enabled, onChanged: _handleBackupChanged)
]
),
new DrawerItem(
children: [
new Flex([
new Text('Height'),
new Text("6'2\"", style: Theme.of(this).text.caption),
], direction: FlexDirection.vertical, alignItems: FlexAlignItems.start)
]
),
])
)
)
);
}
Widget build() {
return new Scaffold(
toolbar: buildToolBar(),
body: buildSettingsPane()
);
}
}
material-design-icons:
- name: action/assessment
- name: action/help
- name: action/settings
- name: content/add
- name: maps/directions_run
- name: navigation/arrow_back
- name: navigation/menu
- name: navigation/more_vert
- name: av/stop
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//sky/build/sky_app.gni")
sky_app("game") {
main_dart = "main.dart"
manifest = "sky.yaml"
if (is_android) {
apk_name = "Asteroids"
deps = [
"//sky/sdk/example/game/apk:resources",
]
}
}
Assets for this game are taken from Galactic Guardian:
https://github.com/slembcke/GalacticGuardian.spritebuilder
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.domokit.asteroids">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
<application android:icon="@mipmap/ic_launcher" android:name="org.domokit.sky.shell.SkyApplication" android:label="Asteroids">
<activity android:name="org.domokit.sky.shell.SkyActivity"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
assert(is_android)
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
android_resources("resources") {
resource_dirs = [ "res" ]
android_manifest = "AndroidManifest.xml"
}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
{"frames": [
{
"filename": "asteroid_big_0.nrm.png",
"frame": {"x":2,"y":260,"w":200,"h":188},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":200,"h":188},
"sourceSize": {"w":200,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_0.png",
"frame": {"x":260,"y":193,"w":200,"h":167},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":21,"w":200,"h":167},
"sourceSize": {"w":200,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_1.nrm.png",
"frame": {"x":451,"y":2,"w":204,"h":166},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":204,"h":166},
"sourceSize": {"w":204,"h":166},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_1.png",
"frame": {"x":657,"y":2,"w":204,"h":166},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":204,"h":166},
"sourceSize": {"w":204,"h":166},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_2.nrm.png",
"frame": {"x":462,"y":170,"w":194,"h":165},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":194,"h":165},
"sourceSize": {"w":194,"h":165},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_big_2.png",
"frame": {"x":658,"y":170,"w":194,"h":165},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":2,"w":194,"h":165},
"sourceSize": {"w":194,"h":167},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_0.nrm.png",
"frame": {"x":204,"y":362,"w":102,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":102,"h":84},
"sourceSize": {"w":102,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_0.png",
"frame": {"x":308,"y":362,"w":102,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":102,"h":84},
"sourceSize": {"w":102,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_1.nrm.png",
"frame": {"x":854,"y":213,"w":96,"h":102},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":102},
"sourceSize": {"w":96,"h":102},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_1.png",
"frame": {"x":854,"y":317,"w":96,"h":102},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":96,"h":102},
"sourceSize": {"w":96,"h":106},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_2.nrm.png",
"frame": {"x":740,"y":337,"w":109,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":109,"h":84},
"sourceSize": {"w":109,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "asteroid_small_2.png",
"frame": {"x":740,"y":423,"w":109,"h":84},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":109,"h":84},
"sourceSize": {"w":109,"h":84},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "explosion_flare.png",
"frame": {"x":863,"y":2,"w":56,"h":209},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":0,"w":56,"h":209},
"sourceSize": {"w":64,"h":256},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "explosion_particle.png",
"frame": {"x":2,"y":450,"w":36,"h":60},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":14,"y":1,"w":36,"h":60},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "explosion_ring.png",
"frame": {"x":2,"y":2,"w":256,"h":256},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":256,"h":256},
"sourceSize": {"w":256,"h":256},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "fire_particle.png",
"frame": {"x":40,"y":450,"w":55,"h":55},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":4,"y":4,"w":55,"h":55},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "laser.png",
"frame": {"x":204,"y":260,"w":37,"h":76},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":37,"h":76},
"sourceSize": {"w":37,"h":76},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "shield.png",
"frame": {"x":260,"y":2,"w":189,"h":189},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":189,"h":189},
"sourceSize": {"w":189,"h":189},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "ship.nrm.png",
"frame": {"x":462,"y":337,"w":137,"h":167},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":137,"h":167},
"sourceSize": {"w":137,"h":167},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "ship.png",
"frame": {"x":601,"y":337,"w":137,"h":167},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":25,"y":10,"w":137,"h":167},
"sourceSize": {"w":188,"h":188},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "star_0.png",
"frame": {"x":204,"y":448,"w":62,"h":62},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":62,"h":62},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "star_1.png",
"frame": {"x":268,"y":448,"w":62,"h":62},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":62,"h":62},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
{
"filename": "star_2.png",
"frame": {"x":332,"y":448,"w":62,"h":62},
"rotated": false,
"trimmed": true,
"spriteSourceSize": {"x":1,"y":1,"w":62,"h":62},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
}],
"meta": {
"app": "http://www.codeandweb.com/texturepacker",
"version": "1.0",
"image": "sprites.png",
"format": "RGBA8888",
"size": {"w":952,"h":512},
"scale": "1",
"smartupdate": "$TexturePacker:SmartUpdate:342fc72defddab59bb356b48894e2931:ecb4b4fa7772ea6a35788ebf670ca27c:1eabdf11f75e3a4fe3147baf7b5be24b$"
}
}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff is collapsed.
part of sprites;
class ColorSequence {
List<Color> colors;
List<double> colorStops;
ColorSequence(this.colors, this.colorStops) {
assert(colors != null);
assert(colorStops != null);
assert(colors.length == colorStops.length);
}
ColorSequence.fromStartAndEndColor(Color start, Color end) {
colors = [start, end];
colorStops = [0.0, 1.0];
}
ColorSequence.copy(ColorSequence sequence) {
colors = new List<Color>.from(sequence.colors);
colorStops = new List<double>.from(sequence.colorStops);
}
ColorSequence.copyWithVariance(ColorSequence sequence, int alphaVar, int redVar, int greenVar, int blueVar) {
colors = new List<Color>();
colorStops = new List<double>.from(sequence.colorStops);
math.Random rand = new math.Random();
for (Color color in sequence.colors) {
int aDelta = ((rand.nextDouble() * 2.0 - 1.0) * alphaVar).toInt();
int rDelta = ((rand.nextDouble() * 2.0 - 1.0) * redVar).toInt();
int gDelta = ((rand.nextDouble() * 2.0 - 1.0) * greenVar).toInt();
int bDelta = ((rand.nextDouble() * 2.0 - 1.0) * blueVar).toInt();
int aNew = (color.alpha + aDelta).clamp(0, 255);
int rNew = (color.red + rDelta).clamp(0, 255);
int gNew = (color.green + gDelta).clamp(0, 255);
int bNew = (color.blue + bDelta).clamp(0, 255);
colors.add(new Color.fromARGB(aNew, rNew, gNew, bNew));
}
}
Color colorAtPosition(double pos) {
assert(pos >= 0.0 && pos <= 1.0);
double lastStop = colorStops[0];
Color lastColor = colors[0];
for (int i = 0; i < colors.length; i++) {
double currentStop = colorStops[i];
Color currentColor = colors[i];
if (pos <= currentStop) {
double blend = (pos - lastStop) / (currentStop - lastStop);
return _interpolateColor(lastColor, currentColor, blend);
}
lastStop = currentStop;
lastColor = currentColor;
}
return colors[colors.length-1];
}
}
Color _interpolateColor(Color a, Color b, double blend) {
double aa = a.alpha.toDouble();
double ar = a.red.toDouble();
double ag = a.green.toDouble();
double ab = a.blue.toDouble();
double ba = b.alpha.toDouble();
double br = b.red.toDouble();
double bg = b.green.toDouble();
double bb = b.blue.toDouble();
int na = (aa * (1.0 - blend) + ba * blend).toInt();
int nr = (ar * (1.0 - blend) + br * blend).toInt();
int ng = (ag * (1.0 - blend) + bg * blend).toInt();
int nb = (ab * (1.0 - blend) + bb * blend).toInt();
return new Color.fromARGB(na, nr, ng, nb);
}
library game;
import 'dart:sky' as sky;
import 'dart:math' as Math;
import 'package:vector_math/vector_math_64.dart';
import 'package:sky/widgets/widget.dart';
import 'sprites.dart';
import 'package:sky/rendering/object.dart';
part 'game_demo_world.dart';
This diff is collapsed.
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of sprites;
class ImageMap {
ImageMap(AssetBundle bundle) : _bundle = bundle;
final AssetBundle _bundle;
final Map<String, Image> _images = new Map<String, Image>();
Future<List<Image>> load(List<String> urls) {
return Future.wait(urls.map(_loadImage));
}
Future<Image> _loadImage(String url) async {
Image image = await _bundle.loadImage(url);
_images[url] = image;
return image;
}
Image getImage(String url) => _images[url];
Image operator [](String url) => _images[url];
}
This diff is collapsed.
part of sprites;
/// The super class of any [Node] that has a size.
///
/// NodeWithSize adds the ability for a node to have a size and a pivot point.
class NodeWithSize extends Node {
/// Changing the size will affect the size of the rendering of the node.
///
/// myNode.size = new Size(1024.0, 1024.0);
Size size;
/// The normalized point which the node is transformed around.
///
/// // Position myNode from is middle top
/// myNode.pivot = new Point(0.5, 0.0);
Point pivot;
/// Creates a new NodeWithSize.
///
/// The default [size] is zero and the default [pivot] point is the origin. Subclasses may change the default values.
///
/// var myNodeWithSize = new NodeWithSize(new Size(1024.0, 1024.0));
NodeWithSize([Size this.size, Point this.pivot]) {
if (size == null) size = Size.zero;
if (pivot == null) pivot = Point.origin;
}
/// Call this method in your [paint] method if you want the origin of your drawing to be the top left corner of the
/// node's bounding box.
///
/// If you use this method you will need to save and restore your canvas at the beginning and
/// end of your [paint] method.
///
/// void paint(PaintingCanvas canvas) {
/// canvas.save();
/// applyTransformForPivot(canvas);
///
/// // Do painting here
///
/// canvas.restore();
/// }
void applyTransformForPivot(PaintingCanvas canvas) {
if (pivot.x != 0 || pivot.y != 0) {
double pivotInPointsX = size.width * pivot.x;
double pivotInPointsY = size.height * pivot.y;
canvas.translate(-pivotInPointsX, -pivotInPointsY);
}
}
bool isPointInside (Point nodePoint) {
double minX = -size.width * pivot.x;
double minY = -size.height * pivot.y;
double maxX = minX + size.width;
double maxY = minY + size.height;
return (nodePoint.x >= minX && nodePoint.x < maxX &&
nodePoint.y >= minY && nodePoint.y < maxY);
}
}
part of sprites;
class _Particle {
Vector2 pos;
Vector2 startPos;
double colorPos;
double deltaColorPos;
double size;
double deltaSize;
double rotation;
double deltaRotation;
double timeToLive;
Vector2 dir;
double radialAccel;
double tangentialAccel;
ColorSequence colorSequence;
}
class ParticleSystem extends Node {
Texture texture;
double life;
double lifeVar;
Point posVar;
double startSize;
double startSizeVar;
double endSize;
double endSizeVar;
double startRotation;
double startRotationVar;
double endRotation;
double endRotationVar;
bool rotateToMovement;
double direction;
double directionVar;
double speed;
double speedVar;
double radialAcceleration;
double radialAccelerationVar;
double tangentialAcceleration;
double tangentialAccelerationVar;
Vector2 gravity;
int maxParticles;
int numParticlesToEmit;
double emissionRate;
bool autoRemoveOnFinish;
ColorSequence colorSequence;
int alphaVar;
int redVar;
int greenVar;
int blueVar;
TransferMode colorTransferMode;
TransferMode transferMode;
List<_Particle> _particles;
double _emitCounter;
// Not yet used:
// double _elapsedTime;
int _numEmittedParticles = 0;
math.Random _rand;
ParticleSystem(this.texture,
{this.life: 1.5,
this.lifeVar: 1.0,
this.posVar: Point.origin,
this.startSize: 2.5,
this.startSizeVar: 0.5,
this.endSize: 0.0,
this.endSizeVar: 0.0,
this.startRotation: 0.0,
this.startRotationVar: 0.0,
this.endRotation: 0.0,
this.endRotationVar: 0.0,
this.rotateToMovement : false,
this.direction: 0.0,
this.directionVar: 360.0,
this.speed: 100.0,
this.speedVar: 50.0,
this.radialAcceleration: 0.0,
this.radialAccelerationVar: 0.0,
this.tangentialAcceleration: 0.0,
this.tangentialAccelerationVar: 0.0,
this.gravity,
this.maxParticles: 100,
this.emissionRate: 50.0,
this.colorSequence,
this.alphaVar: 0,
this.redVar: 0,
this.greenVar: 0,
this.blueVar: 0,
this.colorTransferMode: TransferMode.multiply,
this.transferMode: TransferMode.plus,
this.numParticlesToEmit: 0,
this.autoRemoveOnFinish: true}) {
_particles = new List<_Particle>();
_rand = new math.Random();
_emitCounter = 0.0;
// _elapsedTime = 0.0;
if (gravity == null) gravity = new Vector2.zero();
if (colorSequence == null) colorSequence = new ColorSequence.fromStartAndEndColor(new Color(0xffffffff), new Color(0x00ffffff));
}
void update(double dt) {
// Create new particles
double rate = 1.0 / emissionRate;
if (_particles.length < maxParticles) {
_emitCounter += dt;
}
while(_particles.length < maxParticles
&& _emitCounter > rate
&& (numParticlesToEmit == 0 || _numEmittedParticles < numParticlesToEmit)) {
// Add a new particle
_addParticle();
_emitCounter -= rate;
}
// _elapsedTime += dt;
// Iterate over all particles
for (int i = _particles.length -1; i >= 0; i--) {
_Particle particle = _particles[i];
// Manage life time
particle.timeToLive -= dt;
if (particle.timeToLive <= 0) {
_particles.removeAt(i);
continue;
}
// Update the particle
// Radial acceleration
Vector2 radial;
if (particle.pos[0] != 0 || particle.pos[1] != 0) {
radial = new Vector2.copy(particle.pos).normalize();
} else {
radial = new Vector2.zero();
}
Vector2 tangential = new Vector2.copy(radial);
radial.scale(particle.radialAccel);
// Tangential acceleration
double newY = tangential.x;
tangential.x = -tangential.y;
tangential.y = newY;
tangential.scale(particle.tangentialAccel);
// (gravity + radial + tangential) * dt
Vector2 accel = (gravity + radial + tangential).scale(dt);
particle.dir += accel;
particle.pos += new Vector2.copy(particle.dir).scale(dt);
// Size
particle.size = math.max(particle.size + particle.deltaSize * dt, 0.0);
// Angle
particle.rotation += particle.deltaRotation * dt;
// Color
particle.colorPos = math.min(particle.colorPos + particle.deltaColorPos * dt, 1.0);
}
if (autoRemoveOnFinish && _particles.length == 0 && _numEmittedParticles > 0) {
if (parent != null) removeFromParent();
}
}
void _addParticle() {
_Particle particle = new _Particle();
// Time to live
particle.timeToLive = math.max(life + lifeVar * randMinus1To1(), 0.0);
// Position
Point srcPos = Point.origin;
particle.pos = new Vector2(srcPos.x + posVar.x * randMinus1To1(),
srcPos.y + posVar.y * randMinus1To1());
// Size
particle.size = math.max(startSize + startSizeVar * randMinus1To1(), 0.0);
double endSizeFinal = math.max(endSize + endSizeVar * randMinus1To1(), 0.0);
particle.deltaSize = (endSizeFinal - particle.size) / particle.timeToLive;
// Rotation
particle.rotation = startRotation + startRotationVar * randMinus1To1();
double endRotationFinal = endRotation + endRotationVar * randMinus1To1();
particle.deltaRotation = (endRotationFinal - particle.rotation) / particle.timeToLive;
// Direction
double dirRadians = convertDegrees2Radians(direction + directionVar * randMinus1To1());
Vector2 dirVector = new Vector2(math.cos(dirRadians), math.sin(dirRadians));
double speedFinal = speed + speedVar * randMinus1To1();
particle.dir = dirVector.scale(speedFinal);
// Radial acceleration
particle.radialAccel = radialAcceleration + radialAccelerationVar * randMinus1To1();
// Tangential acceleration
particle.tangentialAccel = tangentialAcceleration + tangentialAccelerationVar * randMinus1To1();
// Color
particle.colorPos = 0.0;
particle.deltaColorPos = 1.0 / particle.timeToLive;
if (alphaVar != 0 || redVar != 0 || greenVar != 0 || blueVar != 0) {
particle.colorSequence = new ColorSequence.copyWithVariance(colorSequence, alphaVar, redVar, greenVar, blueVar);
}
_particles.add(particle);
_numEmittedParticles++;
}
void paint(PaintingCanvas canvas) {
List<RSTransform> transforms = [];
List<Rect> rects = [];
List<Color> colors = [];
for (_Particle particle in _particles) {
// Transform
double scos;
double ssin;
if (rotateToMovement) {
double extraRotation = math.atan2(particle.dir[1], particle.dir[0]);
scos = math.cos(convertDegrees2Radians(particle.rotation) + extraRotation) * particle.size;
ssin = math.sin(convertDegrees2Radians(particle.rotation) + extraRotation) * particle.size;
} else {
scos = math.cos(convertDegrees2Radians(particle.rotation)) * particle.size;
ssin = math.sin(convertDegrees2Radians(particle.rotation)) * particle.size;
}
RSTransform transform = new RSTransform(scos, ssin, particle.pos[0], particle.pos[1]);
transforms.add(transform);
// Rect
Rect rect = texture.frame;
rects.add(rect);
// Color
Color particleColor;
if (particle.colorSequence != null) {
particleColor = particle.colorSequence.colorAtPosition(particle.colorPos);
} else {
particleColor = colorSequence.colorAtPosition(particle.colorPos);
}
colors.add(particleColor);
}
drawAtlas(canvas, texture.image, transforms, rects, colors, TransferMode.modulate,
new Paint()..setTransferMode(transferMode));
}
double randMinus1To1() => _rand.nextDouble() * 2.0 - 1.0;
}
// TODO: Needs bindings to Skia method in SkCanvas (exclude canvas parameter)
void drawAtlas(Canvas canvas, Image image, List<RSTransform> transforms, List<Rect> rects, List<Color> colors,
TransferMode transferMode, Paint paint) {
assert(transforms.length == rects.length && transforms.length == colors.length);
Texture mainTexture = new Texture(image);
for (int i = 0; i < transforms.length; i++) {
RSTransform transform = transforms[i];
Rect rect = rects[i];
Color color = colors[i];
canvas.save();
Matrix4 matrix = new Matrix4(transform.scos, transform.ssin, 0.0, 0.0,
-transform.ssin, transform.scos, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
transform.tx, transform.ty, 0.0, 1.0);
canvas.concat(matrix.storage);
paint.setColorFilter(new ColorFilter.mode(color, transferMode));
paint.color = color;
Texture texture = mainTexture.textureFromRect(rect);
texture.drawTexture(canvas, new Point(-texture.size.width/2.0, -texture.size.height/2.0), paint);
canvas.restore();
}
}
// TODO: Needs bindings to Skia SkRSXform
class RSTransform {
double scos;
double ssin;
double tx;
double ty;
RSTransform(this.scos, this.ssin, this.tx, this.ty);
}
part of sprites;
/// A Sprite is a [Node] that renders a bitmap image to the screen.
class Sprite extends NodeWithSize {
/// The texture that the sprite will render to screen.
///
/// If the texture is null, the sprite will be rendered as a red square
/// marking the bounds of the sprite.
///
/// mySprite.texture = myTexture;
Texture texture;
/// If true, constrains the proportions of the image by scaling it down, if its proportions doesn't match the [size].
///
/// mySprite.constrainProportions = true;
bool constrainProportions = false;
double _opacity = 1.0;
/// The color to draw on top of the sprite, null if no color overlay is used.
///
/// // Color the sprite red
/// mySprite.colorOverlay = new Color(0x77ff0000);
Color colorOverlay;
/// The transfer mode used when drawing the sprite to screen.
///
/// // Add the colors of the sprite with the colors of the background
/// mySprite.transferMode = TransferMode.plusMode;
TransferMode transferMode;
/// Creates a new sprite from the provided [texture].
///
/// var mySprite = new Sprite(myTexture)
Sprite([this.texture]) {
if (texture != null) {
size = texture.size;
pivot = texture.pivot;
} else {
pivot = new Point(0.5, 0.5);
}
}
/// Creates a new sprite from the provided [image].
///
/// var mySprite = new Sprite.fromImage(myImage);
Sprite.fromImage(Image image) {
assert(image != null);
texture = new Texture(image);
size = texture.size;
pivot = new Point(0.5, 0.5);
}
/// The opacity of the sprite in the range 0.0 to 1.0.
///
/// mySprite.opacity = 0.5;
double get opacity => _opacity;
void set opacity(double opacity) {
assert(opacity != null);
assert(opacity >= 0.0 && opacity <= 1.0);
_opacity = opacity;
}
void paint(PaintingCanvas canvas) {
canvas.save();
// Account for pivot point
applyTransformForPivot(canvas);
if (texture != null) {
double w = texture.size.width;
double h = texture.size.height;
if (w <= 0 || h <= 0) return;
double scaleX = size.width / w;
double scaleY = size.height / h;
if (constrainProportions) {
// Constrain proportions, using the smallest scale and by centering the image
if (scaleX < scaleY) {
canvas.translate(0.0, (size.height - scaleX * h) / 2.0);
scaleY = scaleX;
} else {
canvas.translate((size.width - scaleY * w) / 2.0, 0.0);
scaleX = scaleY;
}
}
canvas.scale(scaleX, scaleY);
// Setup paint object for opacity and transfer mode
Paint paint = new Paint();
paint.color = new Color.fromARGB((255.0*_opacity).toInt(), 255, 255, 255);
if (colorOverlay != null) {
paint.setColorFilter(new ColorFilter.mode(colorOverlay, TransferMode.srcATop));
}
if (transferMode != null) {
paint.setTransferMode(transferMode);
}
// Do actual drawing of the sprite
texture.drawTexture(canvas, Point.origin, paint);
} else {
// Paint a red square for missing texture
canvas.drawRect(new Rect.fromLTRB(0.0, 0.0, size.width, size.height),
new Paint()..color = const Color.fromARGB(255, 255, 0, 0));
}
canvas.restore();
}
}
This diff is collapsed.
part of sprites;
/// A widget that uses a [SpriteBox] to render a sprite node tree to the screen.
class SpriteWidget extends OneChildRenderObjectWrapper {
/// The rootNode of the sprite node tree.
///
/// var node = mySpriteWidget.rootNode;
final NodeWithSize rootNode;
/// The transform mode used to fit the sprite node tree to the size of the widget.
final SpriteBoxTransformMode transformMode;
/// Creates a new sprite widget with [rootNode] as its content.
///
/// The widget will setup the coordinate space for the sprite node tree using the size of the [rootNode] in
/// combination with the supplied [transformMode]. By default the letterbox transform mode is used. See
/// [SpriteBoxTransformMode] for more details on the different modes.
///
/// The most common way to setup the sprite node graph is to subclass [NodeWithSize] and pass it to the sprite widget.
/// In the custom subclass it's possible to build the node graph, do animations and handle user events.
///
/// var mySpriteTree = new MyCustomNodeWithSize();
/// var mySpriteWidget = new SpriteWidget(mySpriteTree, SpriteBoxTransformMode.fixedHeight);
SpriteWidget(this.rootNode, [this.transformMode = SpriteBoxTransformMode.letterbox]);
SpriteBox get root => super.root;
SpriteBox createNode() => new SpriteBox(rootNode, transformMode);
void syncRenderObject(SpriteWidget old) {
super.syncRenderObject(old);
// SpriteBox doesn't allow mutation of these properties
assert(rootNode == root.rootNode);
assert(transformMode == root._transformMode);
}
}
\ No newline at end of file
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library sprites;
import 'dart:async';
import 'dart:convert';
import 'dart:math' as math;
import 'dart:sky';
import 'package:sky/animation/curves.dart';
import 'package:sky/base/scheduler.dart' as scheduler;
import 'package:sky/mojo/asset_bundle.dart';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
import 'package:sky/widgets/widget.dart';
import 'package:vector_math/vector_math.dart';
part 'action.dart';
part 'color_secuence.dart';
part 'image_map.dart';
part 'node.dart';
part 'node_with_size.dart';
part 'particle_system.dart';
part 'sprite.dart';
part 'spritesheet.dart';
part 'sprite_box.dart';
part 'sprite_widget.dart';
part 'texture.dart';
part 'util.dart';
part of sprites;
/// A sprite sheet packs a number of smaller images into a single large image.
///
/// The placement of the smaller images are defined by a json file. The larger image and json file is typically created
/// by a tool such as TexturePacker. The [SpriteSheet] class will take a reference to a larger image and a json string.
/// From the image and the string the [SpriteSheet] creates a number of [Texture] objects. The names of the frames in
/// the sprite sheet definition are used to reference the different textures.
class SpriteSheet {
Image _image;
Map<String, Texture> _textures = new Map();
/// Creates a new sprite sheet from an [_image] and a sprite sheet [jsonDefinition].
///
/// var mySpriteSheet = new SpriteSheet(myImage, jsonString);
SpriteSheet(this._image, String jsonDefinition) {
assert(_image != null);
assert(jsonDefinition != null);
JsonDecoder decoder = new JsonDecoder();
Map file = decoder.convert(jsonDefinition);
assert(file != null);
List frames = file["frames"];
for (Map frameInfo in frames) {
String fileName = frameInfo["filename"];
Rect frame = _readJsonRect(frameInfo["frame"]);
bool rotated = frameInfo["rotated"];
bool trimmed = frameInfo["trimmed"];
Rect spriteSourceSize = _readJsonRect(frameInfo["spriteSourceSize"]);
Size sourceSize = _readJsonSize(frameInfo["sourceSize"]);
Point pivot = _readJsonPoint(frameInfo["pivot"]);
var texture = new Texture._fromSpriteFrame(_image, fileName, sourceSize, rotated, trimmed, frame,
spriteSourceSize, pivot);
_textures[fileName] = texture;
}
}
Rect _readJsonRect(Map data) {
num x = data["x"];
num y = data["y"];
num w = data["w"];
num h = data["h"];
return new Rect.fromLTRB(x.toDouble(), y.toDouble(), (x + w).toDouble(), (y + h).toDouble());
}
Size _readJsonSize(Map data) {
num w = data["w"];
num h = data["h"];
return new Size(w.toDouble(), h.toDouble());
}
Point _readJsonPoint(Map data) {
num x = data["x"];
num y = data["y"];
return new Point(x.toDouble(), y.toDouble());
}
/// The image used by the sprite sheet.
///
/// var spriteSheetImage = mySpriteSheet.image;
Image get image => _image;
/// Returns a texture by its name.
///
/// var myTexture = mySpriteSheet["example.png"];
Texture operator [](String fileName) => _textures[fileName];
}
part of sprites;
/// A texture represents a rectangular area of an image and is typically used to draw a sprite to the screen.
///
/// Normally you get a reference to a texture from a [SpriteSheet], but you can also create one from an [Image].
class Texture {
/// The image that this texture is a part of.
///
/// var textureImage = myTexture.image;
final Image image;
/// The logical size of the texture, before being trimmed by the texture packer.
///
/// var textureSize = myTexture.size;
final Size size;
/// The name of the image acts as a tag when acquiring a reference to it.
///
/// myTexture.name = "new_texture_name";
String name;
/// The texture was rotated 90 degrees when being packed into a sprite sheet.
///
/// if (myTexture.rotated) drawRotated();
final bool rotated;
/// The texture was trimmed when being packed into a sprite sheet.
///
/// bool trimmed = myTexture.trimmed
final bool trimmed;
/// The frame of the trimmed texture inside the image.
///
/// Rect frame = myTexture.frame;
final Rect frame;
/// The offset and size of the trimmed texture inside the image.
///
/// Position represents the offset from the logical [size], the size of the rect represents the size of the trimmed
/// texture.
///
/// Rect spriteSourceSize = myTexture.spriteSourceSize;
final Rect spriteSourceSize;
/// The default pivot point for this texture. When creating a [Sprite] from the texture, this is the pivot point that
/// will be used.
///
/// myTexture.pivot = new Point(0.5, 0.5);
Point pivot;
/// Creates a new texture from an [Image] object.
///
/// var myTexture = new Texture(myImage);
Texture(Image image) :
size = new Size(image.width.toDouble(), image.height.toDouble()),
image = image,
trimmed = false,
rotated = false,
frame = new Rect.fromLTRB(0.0, 0.0, image.width.toDouble(), image.height.toDouble()),
spriteSourceSize = new Rect.fromLTRB(0.0, 0.0, image.width.toDouble(), image.height.toDouble()),
pivot = new Point(0.5, 0.5);
Texture._fromSpriteFrame(this.image, this.name, this.size, this.rotated, this.trimmed, this.frame,
this.spriteSourceSize, this.pivot) {
}
Texture textureFromRect(Rect rect, [String name = null]) {
assert(rect != null);
assert(!rotated);
Rect srcFrame = new Rect.fromLTWH(rect.left + frame.left, rect.top + frame.top, rect.size.width, rect.size.height);
Rect dstFrame = new Rect.fromLTWH(0.0, 0.0, rect.size.width, rect.size.height);
return new Texture._fromSpriteFrame(image, name, rect.size, false, false, srcFrame, dstFrame, new Point(0.5, 0.5));
}
void drawTexture(PaintingCanvas canvas, Point position, Paint paint) {
// Account for position
double x = position.x;
double y = position.y;
bool translate = (x != 0 || y != 0);
if (translate) {
canvas.translate(x, y);
}
// Draw the texture
if (rotated) {
// Calculate the rotated frame and spriteSourceSize
Size originalFrameSize = frame.size;
Rect rotatedFrame = frame.topLeft & new Size(originalFrameSize.height, originalFrameSize.width);
Point rotatedSpriteSourcePoint = new Point(
-spriteSourceSize.top - (spriteSourceSize.bottom - spriteSourceSize.top),
spriteSourceSize.left);
Rect rotatedSpriteSourceSize = rotatedSpriteSourcePoint & new Size(originalFrameSize.height, originalFrameSize.width);
// Draw the rotated sprite
canvas.rotate(-math.PI/2.0);
canvas.drawImageRect(image, rotatedFrame, rotatedSpriteSourceSize, paint);
canvas.rotate(math.PI/2.0);
} else {
// Draw the sprite
canvas.drawImageRect(image, frame, spriteSourceSize, paint);
}
// Translate back
if (translate) {
canvas.translate(-x, -y);
}
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/mojo/asset_bundle.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/widget.dart';
import 'package:sky/widgets/task_description.dart';
import 'package:sky/widgets/theme.dart';
import 'lib/game_demo.dart';
import 'lib/sprites.dart';
AssetBundle _initBundle() {
if (rootBundle != null)
return rootBundle;
return new NetworkAssetBundle(Uri.base);
}
final AssetBundle _bundle = _initBundle();
ImageMap _loader;
SpriteSheet _spriteSheet;
GameDemoApp _app;
main() async {
_loader = new ImageMap(_bundle);
await _loader.load([
'assets/nebula.png',
'assets/sprites.png',
'assets/starfield.png',
]);
String json = await _bundle.loadString('assets/sprites.json');
_spriteSheet = new SpriteSheet(_loader['assets/sprites.png'], json);
_app = new GameDemoApp();
runApp(_app);
}
class GameDemoApp extends App {
Widget build() {
// TODO(viktork): The task bar purple is the wrong purple, we may need
// a custom theme swatch to match the purples in the sprites.
ThemeData theme = new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: colors.Purple
);
return new Theme(
data: theme,
child: new TaskDescription(
label: 'Asteroids',
child: new SpriteWidget(
new GameDemoWorld(_app, _loader, _spriteSheet)
)
)
);
}
}
void resetGame() {
_app.scheduleBuild();
}
assets:
- assets/nebula.png
- assets/sprites.json
- assets/sprites.png
- assets/starfield.png
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:sky/widgets/basic.dart';
class HelloWorldApp extends App {
Widget build() {
return new Text('Hello, world!');
}
}
void main() {
runApp(new HelloWorldApp());
}
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//sky/build/sky_app.gni")
sky_app("mine_digger") {
main_dart = "lib/main.dart"
if (is_android) {
apk_name = "MineDigger"
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.domokit.mine_digger">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
<application android:name="org.domokit.sky.shell.SkyApplication" android:label="Mine Digger">
<activity android:name="org.domokit.sky.shell.SkyActivity"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
android:hardwareAccelerated="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
This diff is collapsed.
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky' as sky;
void drawText(sky.Canvas canvas, String lh) {
sky.Paint paint = new sky.Paint();
// offset down
canvas.translate(0.0, 100.0);
// set up the text
sky.Document document = new sky.Document();
sky.Text arabic = document.createText("مرحبا");
sky.Text english = document.createText(" Hello");
sky.Element block = document.createElement('div');
block.style['display'] = 'paragraph';
block.style['font-family'] = 'monospace';
block.style['font-size'] = '50px';
block.style['line-height'] = lh;
block.style['color'] = '#0000A0';
block.appendChild(arabic);
block.appendChild(english);
sky.LayoutRoot layoutRoot = new sky.LayoutRoot();
layoutRoot.rootElement = block;
layoutRoot.maxWidth = sky.view.width - 20.0; // you need to set a width for this to paint
layoutRoot.layout();
// draw a line at the text's baseline
sky.Path path = new sky.Path();
path.moveTo(0.0, 0.0);
path.lineTo(block.maxContentWidth, 0.0);
path.moveTo(0.0, block.alphabeticBaseline);
path.lineTo(block.maxContentWidth, block.alphabeticBaseline);
path.moveTo(0.0, block.height);
path.lineTo(block.maxContentWidth, block.height);
paint.color = const sky.Color(0xFFFF9000);
paint.setStyle(sky.PaintingStyle.stroke);
paint.strokeWidth = 3.0;
canvas.drawPath(path, paint);
// paint the text
layoutRoot.paint(canvas);
}
void main() {
// prepare the rendering
sky.PictureRecorder recorder = new sky.PictureRecorder();
sky.Canvas canvas = new sky.Canvas(recorder, new sky.Rect.fromLTWH(0.0, 0.0, sky.view.width, sky.view.height));
// background
sky.Paint paint = new sky.Paint();
paint.color = const sky.Color(0xFFFFFFFF);
paint.setStyle(sky.PaintingStyle.fill);
canvas.drawRect(new sky.Rect.fromLTRB(0.0, 0.0, sky.view.width, sky.view.height), paint);
canvas.translate(10.0, 0.0);
drawText(canvas, '1.0');
drawText(canvas, 'lh');
// put it on the screen
sky.view.picture = recorder.endRecording();
sky.view.scheduleFrame();
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky';
Picture draw(int a, int r, int g, int b) {
Size size = new Size(view.width, view.height);
PictureRecorder recorder = new PictureRecorder();
Canvas canvas = new Canvas(recorder, Point.origin & size);
double radius = size.shortestSide * 0.45;
Paint paint = new Paint()..color = new Color.fromARGB(a, r, g, b);
canvas.drawCircle(size.center(Point.origin), radius, paint);
return recorder.endRecording();
}
bool handleEvent(Event event) {
if (event.type == "pointerdown") {
view.picture = draw(255, 0, 0, 255);
view.scheduleFrame();
return true;
}
if (event.type == "pointerup") {
view.picture = draw(255, 0, 255, 0);
view.scheduleFrame();
return true;
}
if (event.type == "back") {
print("Pressed back button.");
return true;
}
return false;
}
void main() {
print("Hello, world");
view.picture = draw(255, 0, 255, 0);
view.scheduleFrame();
view.setEventCallback(handleEvent);
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky' as sky;
import 'dart:math' as math;
import 'dart:typed_data';
void beginFrame(double timeStamp) {
sky.Size size = new sky.Size(sky.view.width, sky.view.height);
sky.PictureRecorder recorder = new sky.PictureRecorder();
sky.Canvas canvas = new sky.Canvas(recorder, sky.Point.origin & size);
sky.Paint paint = new sky.Paint();
sky.Point mid = size.center(sky.Point.origin);
double radius = size.shortestSide / 2.0;
canvas.drawPaint(new sky.Paint()..color = const sky.Color(0xFFFFFFFF));
canvas.save();
canvas.translate(-mid.x/2.0, sky.view.height*2.0);
canvas.clipRect(
new sky.Rect.fromLTRB(0.0, -sky.view.height, sky.view.width, radius));
canvas.translate(mid.x, mid.y);
paint.color = const sky.Color.fromARGB(128, 255, 0, 255);
canvas.rotate(math.PI/4.0);
sky.Gradient yellowBlue = new sky.Gradient.linear(
[new sky.Point(-radius, -radius), new sky.Point(0.0, 0.0)],
[const sky.Color(0xFFFFFF00), const sky.Color(0xFF0000FF)]);
canvas.drawRect(new sky.Rect.fromLTRB(-radius, -radius, radius, radius),
new sky.Paint()..setShader(yellowBlue));
// Scale x and y by 0.5.
var scaleMatrix = new Float32List.fromList([
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0,
]);
canvas.concat(scaleMatrix);
paint.color = const sky.Color.fromARGB(128, 0, 255, 0);
canvas.drawCircle(sky.Point.origin, radius, paint);
canvas.restore();
canvas.translate(0.0, 50.0);
var builder = new sky.LayerDrawLooperBuilder()
..addLayerOnTop(
new sky.DrawLooperLayerInfo()
..setOffset(const sky.Offset(150.0, 0.0))
..setColorMode(sky.TransferMode.src)
..setPaintBits(sky.PaintBits.all),
(sky.Paint layerPaint) {
layerPaint.color = const sky.Color.fromARGB(128, 255, 255, 0);
layerPaint.setColorFilter(new sky.ColorFilter.mode(
const sky.Color.fromARGB(128, 0, 0, 255), sky.TransferMode.srcIn));
layerPaint.setMaskFilter(new sky.MaskFilter.blur(
sky.BlurStyle.normal, 3.0, highQuality: true));
})
..addLayerOnTop(
new sky.DrawLooperLayerInfo()
..setOffset(const sky.Offset(75.0, 75.0))
..setColorMode(sky.TransferMode.src)
..setPaintBits(sky.PaintBits.shader),
(sky.Paint layerPaint) {
sky.Gradient redYellow = new sky.Gradient.radial(
new sky.Point(0.0, 0.0), radius/3.0,
[const sky.Color(0xFFFFFF00), const sky.Color(0xFFFF0000)],
null, sky.TileMode.mirror);
layerPaint.setShader(redYellow);
// Since we're don't set sky.PaintBits.maskFilter, this has no effect.
layerPaint.setMaskFilter(new sky.MaskFilter.blur(
sky.BlurStyle.normal, 50.0, highQuality: true));
})
..addLayerOnTop(
new sky.DrawLooperLayerInfo()..setOffset(const sky.Offset(225.0, 75.0)),
(sky.Paint layerPaint) {
// Since this layer uses a DST color mode, this has no effect.
layerPaint.color = const sky.Color.fromARGB(128, 255, 0, 0);
});
paint.setDrawLooper(builder.build());
canvas.drawCircle(sky.Point.origin, radius, paint);
sky.view.picture = recorder.endRecording();
}
void main() {
sky.view.setFrameCallback(beginFrame);
sky.view.scheduleFrame();
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:sky';
PaintingNode paintingNode = null;
Picture draw(int a, int r, int g, int b) {
Rect bounds = new Rect.fromLTRB(0.0, 0.0, view.width, view.height);
Size size = new Size(view.width, view.height);
PictureRecorder recorder = new PictureRecorder();
Canvas canvas = new Canvas(recorder, bounds);
double radius = size.shortestSide * 0.45;
Paint paint = new Paint()..color = new Color.fromARGB(a, r, g, b);
canvas.drawCircle(size.center(Point.origin), radius, paint);
if (paintingNode == null) {
paintingNode = new PaintingNode();
Paint innerPaint = new Paint()..color = new Color.fromARGB(a, 255 - r, 255 - g, 255 - b);
PictureRecorder innerRecorder = new PictureRecorder();
Canvas innerCanvas = new Canvas(innerRecorder, bounds);
innerCanvas.drawCircle(size.center(Point.origin), radius * 0.5, innerPaint);
paintingNode.setBackingDrawable(innerRecorder.endRecordingAsDrawable());
}
canvas.drawPaintingNode(paintingNode, Point.origin);
return recorder.endRecording();
}
bool handleEvent(Event event) {
if (event.type == "pointerdown") {
view.picture = draw(255, 0, 0, 255);
view.scheduleFrame();
return true;
}
if (event.type == "pointerup") {
view.picture = draw(255, 0, 255, 0);
view.scheduleFrame();
return true;
}
return false;
}
void main() {
view.picture = draw(255, 0, 255, 0);
view.scheduleFrame();
view.setEventCallback(handleEvent);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment