diff --git a/Cube4Fun/Pics/Arrows.png b/Cube4Fun/Pics/Arrows.png
new file mode 100644
index 0000000..7241dca
Binary files /dev/null and b/Cube4Fun/Pics/Arrows.png differ
diff --git a/Cube4Fun/Pics/Gradient.png b/Cube4Fun/Pics/Gradient.png
new file mode 100644
index 0000000..d43e8ed
Binary files /dev/null and b/Cube4Fun/Pics/Gradient.png differ
diff --git a/Cube4Fun/Pics/Gradient2.png b/Cube4Fun/Pics/Gradient2.png
new file mode 100644
index 0000000..230a951
Binary files /dev/null and b/Cube4Fun/Pics/Gradient2.png differ
diff --git a/Cube4Fun/Pics/list-add-2.png b/Cube4Fun/Pics/list-add-2.png
new file mode 100644
index 0000000..69adf24
Binary files /dev/null and b/Cube4Fun/Pics/list-add-2.png differ
diff --git a/Cube4Fun/Pics/list-remove-2.png b/Cube4Fun/Pics/list-remove-2.png
new file mode 100644
index 0000000..f2f85e8
Binary files /dev/null and b/Cube4Fun/Pics/list-remove-2.png differ
diff --git a/Cube4Fun/Pics/media-playback-pause-5.png b/Cube4Fun/Pics/media-playback-pause-5.png
new file mode 100644
index 0000000..39cce36
Binary files /dev/null and b/Cube4Fun/Pics/media-playback-pause-5.png differ
diff --git a/Cube4Fun/Pics/media-playback-start-5.png b/Cube4Fun/Pics/media-playback-start-5.png
new file mode 100644
index 0000000..b58577c
Binary files /dev/null and b/Cube4Fun/Pics/media-playback-start-5.png differ
diff --git a/Cube4Fun/Pics/media-seek-backward-5.png b/Cube4Fun/Pics/media-seek-backward-5.png
new file mode 100644
index 0000000..cc4e632
Binary files /dev/null and b/Cube4Fun/Pics/media-seek-backward-5.png differ
diff --git a/Cube4Fun/Pics/media-seek-forward-5.png b/Cube4Fun/Pics/media-seek-forward-5.png
new file mode 100644
index 0000000..ef96448
Binary files /dev/null and b/Cube4Fun/Pics/media-seek-forward-5.png differ
diff --git a/Cube4Fun/Pics/media-skip-backward-5.png b/Cube4Fun/Pics/media-skip-backward-5.png
new file mode 100644
index 0000000..af3447f
Binary files /dev/null and b/Cube4Fun/Pics/media-skip-backward-5.png differ
diff --git a/Cube4Fun/Pics/media-skip-forward-5.png b/Cube4Fun/Pics/media-skip-forward-5.png
new file mode 100644
index 0000000..c19c35a
Binary files /dev/null and b/Cube4Fun/Pics/media-skip-forward-5.png differ
diff --git a/Cube4Fun/Pics/view-sidetree.png b/Cube4Fun/Pics/view-sidetree.png
new file mode 100644
index 0000000..ef6524f
Binary files /dev/null and b/Cube4Fun/Pics/view-sidetree.png differ
diff --git a/Cube4Fun/src/Animations.swift b/Cube4Fun/src/Animations.swift
new file mode 100644
index 0000000..4451152
--- /dev/null
+++ b/Cube4Fun/src/Animations.swift
@@ -0,0 +1,325 @@
+//
+// Animations.swift
+// Cube4Fun
+//
+// Created by Nikolai Rinas on 07.04.15.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+
+// Constants
+let AnimName = "AnimName"
+let AnimKey = "AnimKey"
+let AnimDuration = "AnimDur"
+let AnimSpeed = "AnimSpeed"
+let AnimFrames = "AnimData"
+
+class Animations: NSObject {
+
+ let _emptyFrame: [UInt8] = [
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255]
+
+ var _displayedFrame: Int = 1;
+// var _frameCount: UInt32 = 1;
+// var _oneFrame: NSMutableData = NSMutableData() // == byte[] array
+// var _emptyAnimation: NSMutableDictionary = NSMutableDictionary()
+ var _animationArray: [NSMutableDictionary] = [NSMutableDictionary]()
+ var _animationSelected: Int = 0
+ let _minSendDelay: NSTimeInterval = 0.200 // fastes speed 200 milliseconds
+ let maxFrameSpeed = 3000 // the lowest possible speed allowed
+ let minFrameSpeed = 100 // the fastest possible speed allowed
+ let frameSpeedStep = 100 // how fast increase or decrease speed
+// var _playSendDelay: NSTimeInterval = 0.5 // 500 milliseconds as default
+ var _copyFrameBuffer: [UInt8] = [UInt8]()
+
+
+ override init() {
+ super.init()
+ // Show the first frame
+ _displayedFrame = 1
+ // Append empty animation
+ self.addAnimation()
+ // Set visible animation
+ _animationSelected = 0
+ // Init Buffer
+ for ( var i = 0; i < 64 ; ++i ) {
+ _copyFrameBuffer.append(255)
+ }
+ }
+
+ // How much animations do we have
+ func count() -> (Int) {
+ return _animationArray.count
+ }
+
+ func sendFrame() {
+ let time = NSDate.timeIntervalSinceReferenceDate()
+
+ if (_previousUpdateTime == 0.0) {
+ _previousUpdateTime = time;
+ }
+ // need to do this because of rounding issues
+ let deltaTime: Int = Int( round( (time - _previousUpdateTime) * 10 ) * 100);
+
+ //var ms = Int((time % 1) * 1000)
+ if ( _playAllFrames ) {
+ //println("Delta: \(deltaTime) Speed: \(__animations.animationSpeedInt())")
+ if ( deltaTime >= __animations.animationSpeedInt() ){
+ _previousUpdateTime = time;
+ if (self.getAnimationFrameID() >= self.getAnimationFrameCount()) {
+ _gameView.firstButtonPressed()
+ }else{
+ _gameView.nextButtonPressed()
+ }
+ CubeNetworkObj.updateFrame(self.getAnimDataSelected(), count: UInt32(self.getAnimationFrameID()))
+
+ }
+ }else{
+ CubeNetworkObj.updateFrame(self.getAnimDataSelected(), count: UInt32(self.getAnimationFrameID()))
+ }
+ }
+
+ func loadAnimations(animArray: NSArray) {
+ // clear the array first
+ _animationArray.removeAll(keepCapacity: true)
+ for ( var i=0; i (NSDictionary) {
+ //println(_animationArray.count)
+ let myAnimation = _animationArray[id] as NSDictionary
+ return myAnimation
+ }
+ func getAnimations() -> ([NSDictionary]) {
+ return _animationArray as [NSDictionary];
+ }
+
+ func getAnimationName(id: Int) -> (String) {
+ let value = (self.getAnimation(id)).objectForKey(AnimName) as! String
+ return value
+ }
+ func setAnimationName(id: Int, value: String) {
+ (self.getAnimation(id)).setValue(value, forKey: AnimName)
+ }
+
+ func getAnimationKey(id: Int) -> (String) {
+ let value = (self.getAnimation(id)).objectForKey(AnimKey) as! String
+ return value
+ }
+ func setAnimationKey(id: Int, value: String) {
+ (self.getAnimation(id)).setValue(value, forKey: AnimKey)
+ }
+
+ func getAnimationDuration(id: Int) -> (Int) {
+ let value = (self.getAnimation(id)).objectForKey(AnimDuration) as! Int
+ return value
+ }
+ func setAnimationDuration(id: Int, value: Int) {
+ (self.getAnimation(id)).setValue(value, forKey: AnimDuration)
+ }
+
+ func getAnimationSpeed(id: Int) -> (Int) {
+ let value = (self.getAnimation(id)).objectForKey(AnimSpeed) as! Int
+ return value
+ }
+ func setAnimationSpeed(id: Int, value: Int) {
+ (self.getAnimation(id)).setValue(value, forKey: AnimSpeed)
+ }
+
+ func getAnimationFrameCount() -> (Int) {
+ return self.getAnimationFrameCount(_animationSelected)
+ }
+ func getAnimationFrameCount(id: Int) -> (Int) {
+ let myFrames: NSMutableData = (self.getAnimation(id)).objectForKey(AnimFrames) as! NSMutableData
+ return (myFrames.length / 64)
+ //let value = (self.getAnimation(id)).objectForKey("AnimFrames") as Int
+ //return value
+ }
+ func getAnimationFrameID() -> Int {
+ return _displayedFrame
+ }
+ func setAnimationFrameID(id: Int) {
+ _displayedFrame = id
+ }
+
+ func setSelectedAnimationID(id: Int) {
+ if id >= 0 {
+ _animationSelected = id
+ _displayedFrame = 1
+ }
+ }
+ func getSelectedAnimationID() -> (Int) {
+ return _animationSelected
+ }
+ func deleteSelected() {
+ _animationArray.removeAtIndex(_animationSelected)
+ if ( _animationSelected == 0 && _animationArray.count == 0 ) { // last Frame
+ self.addAnimation()
+ }
+ }
+ func moveUpSelected() {
+ if ( _animationSelected > 0 ) {
+ _animationArray.insert(_animationArray[_animationSelected], atIndex: _animationSelected-1)
+ _animationArray.removeAtIndex(_animationSelected+1)
+ }
+ }
+ func moveDownSelected() {
+ if (_animationSelected < _animationArray.count - 1) {
+ _animationArray.insert(_animationArray[_animationSelected+1], atIndex: _animationSelected)
+ _animationArray.removeAtIndex(_animationSelected+2)
+ }
+ }
+
+ func addAnimation() {
+ _animationArray.append(self.newAnimation())
+ println("append Animation count: \(_animationArray.count)")
+ }
+ func newAnimation() -> (NSMutableDictionary) {
+ println("create new animation")
+ return [AnimName: "Animation1", AnimKey: "1=anim1", AnimDuration: 10, AnimSpeed: 500, AnimFrames: self.newFrame()]
+ }
+ func newFrame() -> (NSMutableData) {
+ println("create new frame")
+ return NSMutableData(bytes: _emptyFrame, length: 64)
+ }
+ func addFrame() {
+ let myData: NSMutableData = (self.getAnimation(_animationSelected)).objectForKey(AnimFrames) as! NSMutableData
+ myData.appendBytes(_emptyFrame, length: 64)
+ }
+ func removeFrame() {
+ if self.getAnimationFrameCount() > 1 {
+ let myData: NSMutableData = (self.getAnimation(_animationSelected)).objectForKey(AnimFrames) as! NSMutableData
+ let myLength = myData.length
+ myData.length = myLength - 64 // remove one frame
+ }
+ }
+
+ func animationSpeedInt() -> Int {
+ let frameSpeed: Int = (self.getAnimation(_animationSelected)).objectForKey(AnimSpeed) as! Int
+ return frameSpeed
+ }
+ func animationSpeedFloat() -> NSTimeInterval {
+ let frameSpeed: Int = (self.getAnimation(_animationSelected)).objectForKey(AnimSpeed) as! Int
+ let mySpeed: NSTimeInterval = NSTimeInterval(Float(frameSpeed)/1000)
+ return mySpeed
+ }
+ func increaseSpeed() {
+ let frameSpeed: Int = (self.getAnimation(_animationSelected)).objectForKey(AnimSpeed) as! Int
+ if frameSpeed < maxFrameSpeed {
+ (self.getAnimation(_animationSelected)).setValue(frameSpeed+frameSpeedStep, forKey: AnimSpeed)
+ }
+ }
+ func decreaseSpeed() {
+ let frameSpeed: Int = (self.getAnimation(_animationSelected)).objectForKey(AnimSpeed) as! Int
+ if frameSpeed > minFrameSpeed {
+ (self.getAnimation(_animationSelected)).setValue(frameSpeed-frameSpeedStep, forKey: AnimSpeed)
+ }
+ }
+
+ func gotoLastFrame() {
+ self.setAnimationFrameID(self.getAnimationFrameCount())
+ }
+ func gotoFirstFrame() {
+ self.setAnimationFrameID(1)
+ }
+ func gotoNextFrame() {
+ if self.getAnimationFrameID() < self.getAnimationFrameCount() {
+ self.setAnimationFrameID(self.getAnimationFrameID()+1)
+ }
+ }
+ func gotoPrevFrame() {
+ if self.getAnimationFrameID() > 1 {
+ self.setAnimationFrameID(self.getAnimationFrameID()-1)
+ }
+ }
+
+
+ func getMinSendDelay() -> (NSTimeInterval) {
+ return _minSendDelay
+ }
+
+ func getAnimDataSelected() -> (UnsafePointer) {
+ let myData: NSMutableData = (self.getAnimation(_animationSelected)).objectForKey(AnimFrames) as! NSMutableData
+ let byteArray = UnsafePointer(myData.bytes)
+ return byteArray
+ }
+
+ func getAnimData(id: Int) -> (UnsafePointer) {
+ let myData: NSMutableData = (self.getAnimation(id)).objectForKey(AnimFrames) as! NSMutableData
+ let byteArray = UnsafePointer(myData.bytes)
+ return byteArray
+ }
+
+ func getAnimDataLength(id: Int) -> Int {
+ let myFrames: NSMutableData = (self.getAnimation(id)).objectForKey(AnimFrames) as! NSMutableData
+ return myFrames.length
+ }
+
+ func setLEDColor(color: UInt8, led: Int) {
+ //println("Led pressed: \(led)")
+ var myByte: [UInt8] = [color]
+ let myData: NSMutableData = (self.getAnimation(_animationSelected)).objectForKey(AnimFrames) as! NSMutableData
+ let bytePosition = NSMakeRange(((self.getAnimationFrameID()-1)*64)+led, 1)
+ myData.replaceBytesInRange(bytePosition, withBytes: myByte)
+
+ // Send updated frame
+ self.sendFrame()
+ }
+
+ func getLEDColor(pos: Int) -> (UInt8) {
+ let myData = self.getAnimDataSelected()
+ return myData[pos]
+ }
+
+ func clearLEDColor() {
+ //var myByte: [UInt8] = [255]
+ let myData: NSMutableData = (self.getAnimation(_animationSelected)).objectForKey(AnimFrames) as! NSMutableData
+ myData.replaceBytesInRange(NSMakeRange((self.getAnimationFrameID()-1)*64, 64), withBytes: _emptyFrame)
+ }
+
+ func copyDisplayedFrame() {
+ let myData = self.getAnimDataSelected()
+ var animFrameCount = (self.getAnimationFrameID()-1)*64
+ for ( var i = 0 ; i < 64 ; ++i ) {
+ _copyFrameBuffer[i] = myData[animFrameCount]
+ ++animFrameCount
+ }
+ }
+ func pasteDisplayedFrame() {
+ let myData: NSMutableData = (self.getAnimation(_animationSelected)).objectForKey(AnimFrames) as! NSMutableData
+ myData.replaceBytesInRange(NSMakeRange((self.getAnimationFrameID()-1)*64, 64), withBytes: _copyFrameBuffer)
+ }
+}
diff --git a/Cube4Fun/src/AnimationsController.swift b/Cube4Fun/src/AnimationsController.swift
new file mode 100644
index 0000000..02b8c4f
--- /dev/null
+++ b/Cube4Fun/src/AnimationsController.swift
@@ -0,0 +1,241 @@
+//
+// ProjectController.swift
+// Cube4Fun
+//
+// Created by Nikolai Rinas on 02.04.15.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+import Cocoa
+import Foundation
+
+//let _emptyAnimation: NSMutableDictionary = ["AnimName": "Animation1", "AnimKey": "1=anim1", "AnimDur": 1, "AnimSpeed": 500, "AnimFrames": 1]
+
+/*
+var dataArray: [NSMutableDictionary] = [["AnimName": "Animation1", "AnimKey": "1=anim1", "AnimDur": 3, "AnimSpeed": 700, "AnimFrames": 12],
+ ["AnimName": "Animation2", "AnimKey": "1=anim2", "AnimDur": 7, "AnimSpeed": 1700, "AnimFrames": 17],
+ ["AnimName": "Animation3", "AnimKey": "1=anim3", "AnimDur": 1, "AnimSpeed": 500, "AnimFrames": 22],
+ ["AnimName": "Animation4", "AnimKey": "1=anim4", "AnimDur": 10, "AnimSpeed": 500, "AnimFrames": 32],
+ ["AnimName": "Animation5", "AnimKey": "1=anim5", "AnimDur": 23, "AnimSpeed": 500, "AnimFrames": 18],
+ ["AnimName": "Animation6", "AnimKey": "1=anim6", "AnimDur": 2, "AnimSpeed": 1000, "AnimFrames": 52]];
+*/
+
+//var _animationArray: [NSMutableDictionary] = [NSMutableDictionary]();
+//var _selectedAnimation: Int = 0;
+
+var __tableView: NSTableView = NSTableView()
+
+class AnimationsController: NSObject, NSTableViewDataSource, NSTableViewDelegate {
+
+ @IBOutlet weak var myTableView: NSTableView!
+
+ override func awakeFromNib() {
+ super.awakeFromNib()
+ __tableView = myTableView
+ }
+
+ func numberOfRowsInTableView(tableView: NSTableView) -> Int {
+ let numberOfRows:Int = __animations.count() // _animationArray.count
+ return numberOfRows
+ }
+
+ func tableView(tableView: NSTableView, objectValueForTableColumn tableColumn: NSTableColumn?, row: Int) -> AnyObject? {
+ //let object: NSDictionary = __animations.getAnimation(row) //_animationArray[row] as NSDictionary
+ //println(object)
+ let column: String = tableColumn?.identifier as String!
+ if column == "AnimName" {
+ return __animations.getAnimationName(row)
+ //let value = object.objectForKey(column) as String
+ //return value
+ }
+ if column == "AnimKey" {
+ return __animations.getAnimationKey(row)
+ //let value = object.objectForKey(column) as String
+ //return value
+ }
+ if column == "AnimDur" {
+ return __animations.getAnimationDuration(row)
+ //let value = object.objectForKey(column) as Int
+ //return value
+ }
+ if column == "AnimSpeed" {
+ return __animations.getAnimationSpeed(row)
+ //let value = object.objectForKey(column) as Int
+ //return value
+ }
+ if column == "AnimFrames" {
+ return __animations.getAnimationFrameCount(row)
+ //let value = object.objectForKey(column) as Int
+ //return value
+ }
+
+ return column
+ }
+
+
+ func tableViewSelectionDidChange(notification: NSNotification) {
+ let view: NSTableView = notification.object as! NSTableView
+ __animations.setSelectedAnimationID(view.selectedRow)
+
+ _gameView.resetView()
+ //let myCubeController: GameViewController = _animationsWindow.contentViewController as! GameViewController
+ //let myCubeView: GameView = myCubeController.view as! GameView
+ //myCubeView.resetView()
+
+ //_selectedAnimation = view.selectedRow
+
+ //println("klicked \(view.selectedRow)")
+ }
+
+ func tableView(tableView: NSTableView, setObjectValue object: AnyObject?, forTableColumn tableColumn: NSTableColumn?, row: Int) {
+ let column: String = tableColumn?.identifier as String!
+ //println("Object: \(object) Key: \((tableColumn?.identifier)!)" )
+
+ let value = object! as! NSString
+ if column == "AnimName" {
+ __animations.setAnimationName(row, value: value as String)
+ //_animationArray[row].setObject(value, forKey: (tableColumn?.identifier)!)
+ }
+ if column == "AnimKey" {
+ __animations.setAnimationKey(row, value: value as String)
+ //_animationArray[row].setObject(value, forKey: (tableColumn?.identifier)!)
+ }
+ if column == "AnimDur" {
+ __animations.setAnimationDuration(row, value: value.integerValue)
+ //_animationArray[row].setObject(value.integerValue, forKey: (tableColumn?.identifier)!)
+ }
+ if column == "AnimSpeed" {
+ __animations.setAnimationSpeed(row, value: value.integerValue)
+ //_animationArray[row].setObject(value.integerValue, forKey: (tableColumn?.identifier)!)
+ }
+
+ _gameView.resetView()
+
+ //if column == "AnimFrames" {
+ // _animationArray[row].setObject(value.integerValue, forKey: (tableColumn?.identifier)!)
+ //}
+ }
+
+ @IBAction func addNewAnimation(sender: AnyObject) {
+ __animations.addAnimation()
+ myTableView.reloadData()
+ }
+
+ @IBAction func delNewAnimation(sender: AnyObject) {
+ __animations.deleteSelected()
+ myTableView.reloadData()
+ }
+
+ @IBAction func moveUpItem(send: AnyObject) {
+ if ( __animations.getSelectedAnimationID() > 0 ) {
+ __animations.moveUpSelected()
+ myTableView.reloadData()
+ myTableView.selectRowIndexes(NSIndexSet(index: __animations.getSelectedAnimationID()-1), byExtendingSelection: false)
+ }
+ }
+
+ @IBAction func moveDownItem(send: AnyObject) {
+ if (__animations.getSelectedAnimationID() < __animations.count() - 1) {
+ __animations.moveDownSelected()
+ myTableView.reloadData()
+ myTableView.selectRowIndexes(NSIndexSet(index: __animations.getSelectedAnimationID()+1), byExtendingSelection: false)
+ }
+ }
+
+ func convertInt16(value: UInt16) -> ([UInt8]) {
+ var array: [UInt8] = [0,0]
+ array[0] = UInt8(value & 0x000000ff);
+ array[1] = UInt8((value & 0x0000ff00) >> 8);
+ return array;
+ }
+
+ func convertInt32(value: UInt32) -> ([UInt8]) {
+ var array: [UInt8] = [0,0,0,0]
+ array[0] = UInt8(value & 0x000000ff);
+ array[1] = UInt8((value & 0x0000ff00) >> 8);
+ array[2] = UInt8((value & 0x00ff0000) >> 16);
+ array[3] = UInt8((value & 0xff000000) >> 24);
+ return array;
+ }
+
+ @IBAction func exportAnimations(send: AnyObject) {
+ var sendData: [UInt8] = [UInt8]()
+ println("Import button pressed")
+
+ // for each animation
+ for ( var i = 0; i < __animations.count(); ++i ) {
+ // Create header line per animation
+ // Syntax: ,F,\n
+
+ // Key
+ sendData.append(UInt8(ascii: ","))
+ sendData.append(UInt8(ascii: "F"))
+ let key = __animations.getAnimationKey(i)
+ let keyArray: NSData = key.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: true)!
+ let keyBytes: UnsafePointer = UnsafePointer(keyArray.bytes)
+ for (var j = 0; j < keyArray.length; ++j) {
+
+ if keyBytes[j] != UInt8(ascii: "\n") && keyBytes[j] != UInt8(ascii: "\r" ) { // ignore line breaks in the key
+ sendData.append(UInt8(keyBytes[j]))
+ }
+ }
+ sendData.append(UInt8(ascii: ","))
+
+ // Playtime
+ let playTime: [UInt8] = convertInt16(UInt16(__animations.getAnimationDuration(i)))
+ sendData.append(playTime[0])
+ sendData.append(playTime[1])
+
+ // Speed
+ let playSpeed: [UInt8] = convertInt16(UInt16(__animations.getAnimationSpeed(i)))
+ sendData.append(playSpeed[0])
+ sendData.append(playSpeed[1])
+
+ // Frames
+ let playFrames: [UInt8] = convertInt16(UInt16(__animations.getAnimationFrameCount(i)))
+ sendData.append(playFrames[0])
+ sendData.append(playFrames[1])
+
+ // End line
+ sendData.append(UInt8(ascii: "\n"))
+
+ // Append frame, separated by new-Line
+ let animData = __animations.getAnimData(i)
+ for ( var count = 1; count <= __animations.getAnimDataLength(i); ++count) {
+ sendData.append(animData[count-1])
+ // End line for each frame
+ if ( (count % 64) == 0 ) {
+ sendData.append(UInt8(ascii: "\n"))
+ }
+ }
+
+
+ }
+
+
+ // Calculate overall data to send
+
+
+ // Send data
+ CubeNetworkObj.sendBytes(sendData , count: UInt32(sendData.count))
+
+ }
+
+ /*
+ @IBAction func closeButtonClicked(sender: AnyObject ) {
+ animationsWindow.close()
+ }
+*/
+}
diff --git a/Cube4Fun/src/AppDelegate.swift b/Cube4Fun/src/AppDelegate.swift
new file mode 100644
index 0000000..a09c1c1
--- /dev/null
+++ b/Cube4Fun/src/AppDelegate.swift
@@ -0,0 +1,178 @@
+//
+// AppDelegate.swift
+// Cube4Fun
+//
+// Created by Nikolai Rinas on 27.03.15.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+import Cocoa
+
+var _animationsWindow: NSWindow = NSWindow()
+var _cubeWindow: NSWindow = NSWindow()
+var _prefWindow: NSWindow = NSWindow()
+var __animations: Animations = Animations()
+var __prefData: Preferences = Preferences()
+
+@NSApplicationMain
+class AppDelegate: NSObject, NSApplicationDelegate, NSTextFieldDelegate {
+
+ @IBOutlet weak var window: NSWindow!
+ @IBOutlet weak var animationsWindow: NSWindow!
+ @IBOutlet weak var preferencesWindow: NSWindow!
+ @IBOutlet weak var myMenu: NSMenu!
+
+ @IBOutlet weak var levelInd: NSProgressIndicator!
+ @IBOutlet weak var ipAddr: NSTextField!
+ @IBOutlet weak var port: NSTextField!
+ @IBOutlet weak var waitAnim: NSProgressIndicator!
+
+ func applicationDidFinishLaunching(aNotification: NSNotification) {
+ // Insert code here to initialize your application
+ _animationsWindow = animationsWindow
+ _cubeWindow = window
+ _prefWindow = preferencesWindow
+ //__animations.initialize()
+
+ port.stringValue = String(__prefData.portNR())
+ ipAddr.stringValue = __prefData.ipAddr()
+ if CubeNetworkObj.connected() {
+ showConnActive(true)
+ }else{
+ showConnActive(false)
+ }
+ }
+
+ func applicationShouldTerminate(sender: NSApplication) -> NSApplicationTerminateReply {
+ CubeNetworkObj.closeConnection()
+ return NSApplicationTerminateReply.TerminateNow
+ }
+
+ @IBAction func saveDocument(sender: AnyObject) {
+ let mySavePanel: NSSavePanel = NSSavePanel()
+ mySavePanel.allowedFileTypes = ["plist"]
+ mySavePanel.beginWithCompletionHandler { (result: Int) -> Void in
+ if result == NSFileHandlingPanelOKButton {
+ let exportedFileURL = mySavePanel.URL
+ // Save the data. What you do depends on your app.
+ let myAnimArray: NSMutableArray = NSMutableArray()
+ myAnimArray.addObjectsFromArray(__animations.getAnimations())
+ myAnimArray.writeToURL(exportedFileURL!, atomically: true)
+ //let myAnimation: NSDictionary = NSDictionary(dictionary: __animations.getAnimations())
+
+
+ // Don't just paste this code in your app as your app
+ // probably doesn't have a createPDF() method. self.createPDF(exportedFileURL)
+ }
+ } // End block
+ println("save pressed")
+ }
+
+ @IBAction func openDocument(sender: AnyObject) {
+ let myOpenPanel: NSOpenPanel = NSOpenPanel()
+ myOpenPanel.allowedFileTypes = ["plist"]
+ myOpenPanel.beginWithCompletionHandler { (result: Int) -> Void in
+ if result == NSFileHandlingPanelOKButton {
+ let importedFileURL = myOpenPanel.URL
+ //let myAnimationsDict: NSMutableDictionary = NSMutableDictionary(contentsOfURL: importedFileURL!)!
+ let myAnimArray: NSMutableArray = NSMutableArray(contentsOfURL: importedFileURL!)!
+ __animations.loadAnimations(myAnimArray)
+ }
+ } // End block
+ }
+
+ @IBAction func openPreferences(send: AnyObject) {
+ preferencesWindow.setIsVisible(true)
+ }
+
+ @IBAction func testIPConnection(send: AnyObject) {
+ //println("TestIP Button clicked")
+
+ if CubeNetworkObj.connected() {
+ CubeNetworkObj.closeConnection()
+ }
+ if CubeNetworkObj.openConnection(__prefData.ipAddr(), port: UInt32(__prefData.portNR())) {
+ showConnActive(true)
+ }else{
+ showConnActive(false)
+ }
+
+ }
+
+ func showConnActive(active: Bool) {
+ if active {
+ levelInd.doubleValue = 100.0
+ }else{
+ levelInd.doubleValue = 0.0
+ }
+ }
+
+ func validIPAddress(ipaddr: String) -> Bool {
+ var valid: Bool = false
+ let validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
+ if ipaddr != "" {
+ if (ipaddr.rangeOfString(validIpAddressRegex, options: .RegularExpressionSearch) != nil) {
+ valid = true;
+ }
+ }
+ return valid
+ }
+
+ func validPortNr(portNr: Int) -> Bool {
+ var valid: Bool = false
+ if portNr < 65536 && portNr > 0 {
+ valid = true
+ }
+ return valid
+ //^(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$
+ }
+
+ override func controlTextDidChange(obj: NSNotification) {
+ let myField: NSTextField = obj.object as! NSTextField
+ if myField.identifier == "IPADDR_FIELD" {
+ if validIPAddress(myField.stringValue) {
+ __prefData.setIPAddr(myField.stringValue)
+ println("Changing ip address field")
+ }
+ }
+ if myField.identifier == "PORTNR_FIELD" {
+ if validPortNr(myField.integerValue) {
+ __prefData.setPortNr(myField.integerValue)
+ println("Changing port number")
+ }
+ }
+ }
+
+ @IBAction func cmdCopyPressed(send: AnyObject) {
+ __animations.copyDisplayedFrame()
+ }
+
+ @IBAction func cmdPastePressed(send: AnyObject) {
+ __animations.pasteDisplayedFrame()
+ _gameView.updateLEDFrame()
+ // Send updated frame
+ __animations.sendFrame()
+ }
+
+ @IBAction func clearLEDs(send: AnyObject) {
+ // Remove from Memory
+ __animations.clearLEDColor()
+ // Update visual
+ _gameView.updateLEDFrame()
+ // Update on a hardware
+ __animations.sendFrame()
+ }
+
+}
diff --git a/Cube4Fun/src/Cube4Fun-Bridging-Header.h b/Cube4Fun/src/Cube4Fun-Bridging-Header.h
new file mode 100644
index 0000000..1659414
--- /dev/null
+++ b/Cube4Fun/src/Cube4Fun-Bridging-Header.h
@@ -0,0 +1,5 @@
+//
+// Use this file to import your target's public headers that you would like to expose to Swift.
+//
+
+#import "ObjCtoCPlusPlus.h"
\ No newline at end of file
diff --git a/Cube4Fun/src/CubeNetwork.cpp b/Cube4Fun/src/CubeNetwork.cpp
new file mode 100644
index 0000000..219a2ff
--- /dev/null
+++ b/Cube4Fun/src/CubeNetwork.cpp
@@ -0,0 +1,368 @@
+//
+// CubeNetwork.cpp
+// Cube4Fun
+//
+// Created by Nikolai Rinas on 28.03.15.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+#include "CubeNetwork.h"
+
+
+#ifdef WIN32
+#include
+#else
+#include
+#endif // win32
+
+using Poco::Net::DialogSocket;
+using Poco::Net::SocketAddress;
+using Poco::Exception;
+
+unsigned char buffer3D[64];
+unsigned char receiveBuffer[32];
+int bytesReceived;
+int i,x;
+unsigned char color;
+DialogSocket ds;
+int frameChange = 0;
+int streamMode = 0; // 0 = off, 1 = frameStream, 2 = writeStream
+
+void sleepcp(int milliseconds) // cross-platform sleep function
+{
+#ifdef WIN32
+ Sleep(milliseconds);
+#else
+ usleep(milliseconds * 1000);
+#endif // win32
+}
+
+bool frame1[3][64] = { {1,0,0,1,
+ 0,0,0,0,
+ 0,0,0,0,
+ 1,0,0,1,
+ 0,0,0,0,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0,
+ 1,0,0,1,
+ 0,0,0,0,
+ 0,0,0,0,
+ 1,0,0,1},
+ {0,0,0,0,
+ 0,0,0,0,
+ 1,0,0,1,
+ 0,0,0,0,
+ 1,0,0,1,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0, //0,1,1,0,
+ 1,0,0,1,
+ 0,0,0,0,
+ 1,0,0,1,
+ 0,0,0,0,
+ 0,0,0,0},
+ {0,0,0,0,
+ 1,0,0,1,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0, //0,1,1,0,
+ 1,0,0,1,
+ 1,0,0,1,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0, //0,1,1,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 1,0,0,1,
+ 0,0,0,0}};
+
+bool connectionEstablished = false;
+
+void byte2uint32(unsigned char* bytes, u_int32_t msgLength) {
+ unsigned char *vp = (unsigned char *)&msgLength;
+ bytes[0] = vp[0]; // int32 to byte array conversion
+ bytes[1] = vp[1];
+ bytes[2] = vp[2];
+ bytes[3] = vp[3];
+}
+
+void msgCloseFrameStream() {
+ try {
+ buffer3D[0] = 's';
+ buffer3D[1] = 'S';
+ ds.sendBytes(buffer3D, 2); // End the stream mode
+ }catch (const Poco::Net::NetException & e){
+ std::cerr << e.displayText() << std::endl;
+ }
+}
+
+void msgOpenFrameStream() {
+ try {
+ buffer3D[0] = 'G';
+ buffer3D[1] = 'E';
+ buffer3D[2] = 'T';
+ buffer3D[3] = ' ';
+ buffer3D[4] = '/';
+ buffer3D[5] = '?';
+ buffer3D[6] = 'S';
+ buffer3D[7] = 's';
+ buffer3D[8] = ' ';
+ ds.sendBytes(buffer3D, 9);
+ }catch (const Poco::Net::NetException & e){
+ std::cerr << e.displayText() << std::endl;
+ }
+}
+
+void msgStartWrite(u_int32_t msgLength) {
+ unsigned char myBuffer[4];
+ byte2uint32(myBuffer, msgLength);
+ try{
+ buffer3D[0] = 'G';
+ buffer3D[1] = 'E';
+ buffer3D[2] = 'T';
+ buffer3D[3] = ' ';
+ buffer3D[4] = '/';
+ buffer3D[5] = '?';
+ buffer3D[6] = 'W';
+ buffer3D[7] = 'w';
+ buffer3D[8] = myBuffer[0]; // int32 to byte array conversion
+ buffer3D[9] = myBuffer[1];
+ buffer3D[10] = myBuffer[2];
+ buffer3D[11] = myBuffer[3];
+ buffer3D[12] = ' ';
+
+ printf("sending Length:\n");
+ printf("0: %u\n", myBuffer[0]);
+ printf("1: %u\n", myBuffer[1]);
+ printf("2: %u\n", myBuffer[2]);
+ printf("3: %u\n", myBuffer[3]);
+
+ ds.sendBytes(buffer3D, 13);
+ }catch (const Poco::Net::NetException & e){
+ std::cerr << e.displayText() << std::endl;
+ }
+}
+
+
+
+
+void testFrame() {
+// for (color=128;color<130;color++) {
+ // Create testframe
+ for (x=0;x<64;x++) {
+ buffer3D[x] = color; // Red frame
+ }
+ if ( color > 128 ) {
+ buffer3D[0]=255;
+ buffer3D[3]=255;
+ buffer3D[12]=255;
+ buffer3D[15]=255;
+
+ buffer3D[48]=255;
+ buffer3D[51]=255;
+ buffer3D[60]=255;
+ buffer3D[63]=255;
+ }else{
+ buffer3D[0]=254;
+ buffer3D[3]=254;
+ buffer3D[12]=254;
+ buffer3D[15]=254;
+
+ buffer3D[48]=254;
+ buffer3D[51]=254;
+ buffer3D[60]=254;
+ buffer3D[63]=254;
+ }
+ ds.sendBytes(buffer3D, 64);
+ // sleepcp(50); // 20 FPS
+ // }
+
+}
+
+
+void testStream2() {
+ int frameChange = 0;
+ while (true) {
+ unsigned char color = rand() % 254;
+ for (i=0;i<64;i++) {
+ if ( frame1[frameChange][i] == 1 ) {
+ buffer3D[i] = color; // Rot
+ }else{
+ buffer3D[i] = 255; // Aus
+ }
+ }
+ ds.sendBytes(buffer3D, 64);
+ sleepcp(1000); // 20 FPS
+ if ( frameChange < 2 ) {
+ frameChange++;
+ }else{
+ frameChange=0;
+ }
+ }
+}
+
+/*
+void CubeNetwork::updateFrame() {
+ unsigned char color = rand() % 254;
+ for (i=0;i<64;i++) {
+ if ( frame1[frameChange][i] == 1 ) {
+ buffer3D[i] = color; // Rot
+ }else{
+ buffer3D[i] = 255; // Aus
+ }
+ }
+ ds.sendBytes(buffer3D, 64);
+ if ( frameChange < 2 ) {
+ frameChange++;
+ }else{
+ frameChange=0;
+ }
+}
+*/
+
+void CubeNetwork::sendBytes(const unsigned char* byteBuffer, unsigned int byteLength) {
+ printf("sendBytes called\n");
+ if ( connectionEstablished) {
+ if ( streamMode == 1 ) {
+ // End the frameStreammode first
+ msgCloseFrameStream();
+ streamMode = 2;
+ }
+ if ( byteBuffer != NULL ) {
+ try {
+ printf("Open connection for writing\n");
+ //ds.connect(SocketAddress("192.168.1.79", 8081));
+ // let arduino knows what to expect
+ msgStartWrite(byteLength);
+ unsigned char myBuffer[4];
+ int ret = ds.receiveRawBytes(myBuffer, 4);
+ printf("received Length:\n");
+ printf("0: %u\n", myBuffer[0]);
+ printf("1: %u\n", myBuffer[1]);
+ printf("2: %u\n", myBuffer[2]);
+ printf("3: %u\n", myBuffer[3]);
+ printf("ret: %u\n", ret);
+
+ // send bytes to write
+ ds.sendBytes(byteBuffer, byteLength);
+ //ds.close();
+ // Reset to the frameStream mode
+ if ( streamMode == 2 ) {
+ msgOpenFrameStream();
+ streamMode = 1;
+ }
+ }catch (const Poco::Net::NetException & e){
+ std::cerr << e.displayText() << std::endl;
+ }
+ }
+ }
+
+}
+
+
+void CubeNetwork::updateFrame(const unsigned char * frameSequence, unsigned int frameCount) {
+ if (connectionEstablished) {
+ // check for empty pointer
+ if ( frameSequence != NULL ) {
+ //for (startFrame = 0; startFrame(ipAddr));
+ Poco::UInt16 portNr = port;
+ try {
+ ds.connect(SocketAddress(ipAddr_str, portNr), Poco::Timespan(10, 0));
+
+ msgOpenFrameStream();
+ streamMode = 1;
+ connectionEstablished = true;
+ }catch (Poco::Net::NetException & e){
+ std::cerr << e.displayText() << std::endl;
+ ds.close();
+ }catch (Poco::TimeoutException & e) {
+ std::cerr << e.displayText() << std::endl;
+ ds.close();
+ }catch (Exception e){
+ std::cerr << e.displayText() << std::endl;
+ ds.close();
+ }
+ return connectionEstablished;
+}
+
+void CubeNetwork::closeConnection() {
+ try {
+ connectionEstablished = false;
+ msgCloseFrameStream();
+ ds.close();
+ }catch (const Poco::Net::NetException & e){
+ std::cerr << e.displayText() << std::endl;
+ }
+ streamMode = 0;
+}
+
+bool CubeNetwork::connected() {
+ return connectionEstablished;
+}
+
+/*
+
+void CubeNetwork::initObjects() {
+ srand((unsigned int)time(NULL));
+
+ try {
+ ds.connect(SocketAddress("192.168.1.79", 8081));
+
+ fillBufferWithMsgStartStream();
+ ds.sendBytes(buffer3D, 9);
+
+
+ //testStream2();
+ testFrame();
+
+ msgCloseFrameStream();
+
+ }catch (const Poco::Net::NetException & e){
+ std::cerr << e.displayText() << std::endl;
+ }
+
+
+ //std::cout << "It works" << std::endl;
+
+}
+
+*/
+//void Performance_CPlusPlus::sortArray(unsigned int num_elements)
diff --git a/Cube4Fun/src/CubeNetwork.h b/Cube4Fun/src/CubeNetwork.h
new file mode 100644
index 0000000..1f78a06
--- /dev/null
+++ b/Cube4Fun/src/CubeNetwork.h
@@ -0,0 +1,46 @@
+//
+// CubeNetwork.h
+// Cube4Fun
+//
+// Created by Nikolai Rinas on 28.03.15.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+#ifndef __Cube4Fun__CubeNetwork__
+#define __Cube4Fun__CubeNetwork__
+
+#include
+#include "Poco/Foundation.h"
+#include "Poco/Net/SocketAddress.h"
+#include "Poco/Net/DialogSocket.h"
+#include "Poco/Net/NetException.h"
+#include "Poco/Exception.h"
+#include /* srand, rand */
+#include /* time */
+#include
+
+class CubeNetwork
+{
+public:
+ static bool connected();
+ //static void initObjects();
+ static void updateFrame(const unsigned char * frameSequence = NULL, unsigned int frameCount = 0);
+ static void sendBytes(const unsigned char* byteBuffer = NULL, u_int32_t byteLength=0);
+ static bool openConnection(const char* ipAddr, unsigned int port);
+ //static void openConnection();
+ static void closeConnection();
+};
+
+#endif /* defined(__Cube4Fun__CubeNetwork__) */
diff --git a/Cube4Fun/src/GameView.swift b/Cube4Fun/src/GameView.swift
new file mode 100644
index 0000000..a448128
--- /dev/null
+++ b/Cube4Fun/src/GameView.swift
@@ -0,0 +1,621 @@
+//
+// GameView.swift
+// Cube4Fun
+//
+// Created by Nikolai Rinas on 27.03.15.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+import SceneKit
+
+var lastMousePos: NSPoint = NSPoint()
+var startAngle: CGFloat = CGFloat()
+var klickedColor: UInt8 = UInt8(1)
+let relativeBarPosition: CGFloat = 500.0
+
+
+class GameView: SCNView {
+
+ var playTimer: NSTimer = NSTimer()
+
+ func scheduleTimer() {
+ playTimer = NSTimer.scheduledTimerWithTimeInterval(__animations.animationSpeedFloat(), target: __animations, selector: Selector("sendFrame"), userInfo: nil, repeats: true)
+ }
+ func resetTimer() {
+ playTimer.invalidate()
+ }
+ func rescheduleTimer() {
+ resetTimer();
+ scheduleTimer();
+ }
+
+ func resetView() {
+ println("Reset view")
+ // goto first frame
+ self.firstButtonPressed()
+
+ // Update speed
+ self.updateSpeedText()
+
+ // Send updated frame
+ __animations.sendFrame()
+ }
+
+ func updateButtonVisibility() {
+ // init
+ var nextFrame = false;
+ var lastFrame = false;
+ var prevFrame = false;
+ var firstFrame = false;
+ var delFrame = false;
+
+ // first Frame, only one Frame
+ // -> no button visible
+ if __animations.getAnimationFrameID() == 1 && __animations.getAnimationFrameCount() == 1 {
+ nextFrame = false;
+ lastFrame = false;
+ prevFrame = false;
+ firstFrame = false;
+ delFrame = false;
+ }
+
+ // first Frame, second exists.
+ if __animations.getAnimationFrameID() == 1 && __animations.getAnimationFrameCount() > 1 {
+ // Visible:
+ nextFrame = true;
+ lastFrame = true;
+ delFrame = true;
+ // Invisible:
+ prevFrame = false;
+ firstFrame = false;
+ }
+
+ // previous Frame exists, no more Frames
+ if __animations.getAnimationFrameID() > 1 && __animations.getAnimationFrameID() == __animations.getAnimationFrameCount() {
+ // Visible:
+ prevFrame = true;
+ firstFrame = true;
+ delFrame = true;
+ // Invisible
+ nextFrame = false;
+ lastFrame = false;
+ }
+
+ // previous Frame exists and next Frame exists {
+ if __animations.getAnimationFrameID() > 1 && __animations.getAnimationFrameID() < __animations.getAnimationFrameCount() {
+ // Visible:
+ prevFrame = true;
+ firstFrame = true;
+ delFrame = true;
+ nextFrame = true;
+ lastFrame = true;
+ }
+
+ if let rootNode = self.scene?.rootNode {
+ for childNode in rootNode.childNodes {
+ let buttonNode: SCNNode = childNode as! SCNNode
+ if buttonNode.name == "myNextFrameButton" {
+ buttonNode.hidden = !nextFrame;
+ }
+ if buttonNode.name == "myPrevFrameButton" {
+ buttonNode.hidden = !prevFrame
+ }
+ if buttonNode.name == "myStartFrameButton" {
+ buttonNode.hidden = !firstFrame
+ }
+ if buttonNode.name == "myLastFrameButton" {
+ buttonNode.hidden = !lastFrame
+ }
+ if buttonNode.name == "myDelFrameButton" {
+ buttonNode.hidden = !delFrame
+ }
+ if buttonNode.name == "myFrameText" {
+ let geometry:SCNText = buttonNode.geometry as! SCNText
+ geometry.string = "Frame: \(__animations.getAnimationFrameID())/\(__animations.getAnimationFrameCount())"
+ }
+
+ }
+ }
+
+ // Send updated frame
+ __animations.sendFrame()
+
+ }
+
+ func updateLEDFrame() {
+ // get actuall frame data
+
+// let data : UnsafePointer = UnsafePointer(myFrames.mutableBytes)
+ //let data = __animations.getAnimDataSelected()
+ //NSMutableData
+ if let rootNode = self.scene?.rootNode {
+ if let cubeNode = rootNode.childNodeWithName("cubeNode", recursively: true) {
+ for myLED in cubeNode.childNodes {
+ if let name:NSString = myLED.name {
+ if name != "myBox" { // LED lamps
+ if let geometry: SCNGeometry = myLED.geometry {
+ let ledID: Int = Int(name.integerValue)
+ if let material: SCNMaterial = geometry.firstMaterial {
+ var color: NSColor = NSColor()
+ let colorPosition: Int = ((__animations.getAnimationFrameID()-1)*64) + ledID
+ let savedColor: UInt8 = __animations.getLEDColor(colorPosition) //data[colorPosition]
+ if savedColor == 255 {
+ color = NSColor.grayColor()
+ }else{
+ let hueColor = CGFloat(savedColor) / 255.0
+ color = NSColor(calibratedHue: hueColor, saturation: 1.0, brightness: 1.0, alpha: 1.0)
+ }
+ material.diffuse.contents = color
+ //println(name)
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ //__animations.sendFrame()
+ }
+
+ func plusButtonPressed() {
+ // Extend the data array with one frame
+ //myFrames.appendBytes(emptyFrame, length: 64)
+ __animations.addFrame()
+
+ // Add frame
+ //myMaxFrameCount++;
+
+ // Goto new frame
+ //myFrameCount = __animations.getAnimationFrameCount();
+ __animations.gotoLastFrame()
+
+ // Update LEDs
+ updateLEDFrame()
+
+ // Update control button visibility
+ updateButtonVisibility()
+ }
+
+ func minusButtonPressed() {
+ // remove one frame from the data array
+ // TODO!
+
+ // Remove frame
+ __animations.removeFrame()
+// if __animations.getAnimationFrameCount() > 1 {
+// myMaxFrameCount--;
+// }
+// if myFrameCount > 1 {
+// myFrameCount--;
+// }
+
+ // Update control button visibility
+ updateButtonVisibility()
+ }
+
+ func prevButtonPressed() {
+// if myFrameCount > 1 {
+// myFrameCount--
+// }
+ __animations.gotoPrevFrame()
+
+ // Update LEDs
+ updateLEDFrame()
+
+ // Update control button visibility
+ updateButtonVisibility()
+ }
+
+ func nextButtonPressed() {
+// if myFrameCount < myMaxFrameCount {
+// myFrameCount++
+// }
+ __animations.gotoNextFrame()
+
+ // Update LEDs
+ updateLEDFrame()
+
+ // Update control button visibility
+ updateButtonVisibility()
+ }
+
+ func firstButtonPressed() {
+ //myFrameCount = 1;
+ __animations.gotoFirstFrame()
+
+ // Update LEDs
+ updateLEDFrame()
+
+ // Update control button visibility
+ updateButtonVisibility()
+ }
+
+ func lastButtonPressed() {
+ __animations.gotoLastFrame()
+
+ // Update LEDs
+ updateLEDFrame()
+
+ // Update control button visibility
+ updateButtonVisibility()
+ }
+
+ func plusSpeedButtonPressed() {
+ __animations.increaseSpeed()
+// if ( _playSendDelay <= 3 ) { // 3 seconds slowest fps
+// _playSendDelay = _playSendDelay + 0.1
+ updateSpeedText()
+// }
+ rescheduleTimer()
+ }
+
+ func minusSpeedButtonPressed() {
+ //println(_playSendDelay)
+ __animations.decreaseSpeed()
+// if ( _playSendDelay > 0.2 ) { // 100ms fastest fps
+// _playSendDelay = _playSendDelay - 0.1
+ updateSpeedText()
+// }
+ rescheduleTimer()
+ }
+
+ func updateSpeedText() {
+ if let rootNode = self.scene?.rootNode {
+ for childNode in rootNode.childNodes {
+ let buttonNode: SCNNode = childNode as! SCNNode
+ if buttonNode.name == "mySpeedText" {
+ let geometry:SCNText = buttonNode.geometry as! SCNText
+ geometry.string = "Speed: \(__animations.animationSpeedInt()) ms"
+ }
+
+ }
+ }
+
+ }
+
+
+ func playButtonPressed() {
+ // Change the button from Play to Pause
+ let myPauseButtonNode: SCNNode = self.scene!.rootNode.childNodeWithName("myPauseButton", recursively: true)!
+ let myPlayButtonNode: SCNNode = self.scene!.rootNode.childNodeWithName("myPlayButton", recursively: true)!
+ myPlayButtonNode.hidden = true
+ myPauseButtonNode.hidden = false
+
+ // Start the animation
+ _playAllFrames = true
+ scheduleTimer();
+ }
+
+ func pauseButtonPressed() {
+ // Change the button from Pause to Play
+ let myPauseButtonNode: SCNNode = self.scene!.rootNode.childNodeWithName("myPauseButton", recursively: true)!
+ let myPlayButtonNode: SCNNode = self.scene!.rootNode.childNodeWithName("myPlayButton", recursively: true)!
+ myPauseButtonNode.hidden = true
+ myPlayButtonNode.hidden = false
+
+ // Stop the animation
+ _playAllFrames = false
+ resetTimer()
+ }
+
+ func openAnimationWindow() {
+ _animationsWindow.setIsVisible(true)
+
+ }
+
+ override func rightMouseDown(theEvent: NSEvent) {
+ let p = self.convertPoint(theEvent.locationInWindow, fromView: nil)
+ if let hitResults = self.hitTest(p, options: nil) {
+ // check that we clicked on at least one object
+ if hitResults.count > 0 {
+ // retrieved the first clicked object
+ let result: AnyObject = hitResults[0]
+ if let node = result.node {
+ if let geom = node.geometry {
+ if let name:NSString = geom.name {
+ if name.integerValue >= 0 && name.integerValue < 64 { // LED lamps
+ let color: NSColor = geom.firstMaterial?.diffuse.contents as! NSColor
+ if color != NSColor.grayColor() {
+ // Make sure we are in range of 0...255
+ let ledColor = (color.hueComponent * 255) % 255
+ if ( ledColor >= 0 && ledColor < 255 ) {
+ klickedColor = UInt8(ledColor)
+ }
+ klickedColor = UInt8 (color.hueComponent * 255)
+ moveArrows(Int(klickedColor))
+ //println(klickedColor)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override func mouseDown(theEvent: NSEvent) {
+ lastMousePos = theEvent.locationInWindow
+ /* Called when a mouse click occurs */
+
+ var ledPressed: Int = 0;
+ var ledColorOn = false;
+
+ // check what nodes are clicked
+ let p = self.convertPoint(theEvent.locationInWindow, fromView: nil)
+ if let hitResults = self.hitTest(p, options: nil) {
+ // check that we clicked on at least one object
+ if hitResults.count > 0 {
+ // retrieved the first clicked object
+ let result: AnyObject = hitResults[0]
+ var anim = true
+
+ // get its material
+ let material = result.node!.geometry!.firstMaterial!
+
+ if let clickedNode = result.node {
+ if clickedNode.name == "myBox" {
+ anim = false
+ }
+ if clickedNode.name == "myPlayButton" && __animations.getAnimationFrameCount() > 1 {
+ playButtonPressed()
+ anim = false
+ }
+ if clickedNode.name == "myPauseButton" {
+ pauseButtonPressed()
+ anim = false
+ }
+ if clickedNode.name == "myAddFrameButton" {
+ plusButtonPressed()
+ }
+ if clickedNode.name == "myDelFrameButton" {
+ minusButtonPressed()
+ }
+ if clickedNode.name == "myPrevFrameButton" {
+ prevButtonPressed()
+ }
+ if clickedNode.name == "myNextFrameButton" {
+ nextButtonPressed()
+ }
+ if clickedNode.name == "myStartFrameButton" {
+ firstButtonPressed()
+ }
+ if clickedNode.name == "myLastFrameButton" {
+ lastButtonPressed()
+ }
+ if clickedNode.name == "myPlusSpeedButton" {
+ plusSpeedButtonPressed()
+ }
+ if clickedNode.name == "myMinusSpeedButton" {
+ minusSpeedButtonPressed()
+ }
+ if clickedNode.name == "myMngAnimationsButton" {
+ openAnimationWindow()
+ }
+ if clickedNode.name == "myColorBar" || clickedNode.name == "myArrows" {
+ let colorInt = Int(round(relativeBarPosition - theEvent.locationInWindow.y))
+ if colorInt < 0 {
+ klickedColor = 0 // Minimum value
+ }else{
+ if colorInt > 253 {
+ klickedColor = 253 // Maximum value
+ }else{
+ klickedColor = UInt8(colorInt)
+ println(klickedColor)
+ }
+ }
+ // Move arrows to the clicked position
+ moveArrows(colorInt)
+
+ //println("BarX: \(barRootPositionX) ClickedX: \(theEvent.locationInWindow.x) ")
+ //println("BarY: \(barRootPositionY) ClickedY: \(theEvent.locationInWindow.y) ")
+
+
+ anim = false
+ }
+ }
+
+ // get its name
+ if let node = result.node {
+ if let geom = node.geometry {
+ if let name:NSString = geom.name {
+ let myGeometry:SCNText = self.scene!.rootNode.childNodeWithName("myDescr", recursively: true)?.geometry as! SCNText
+ // Show touched led
+ myGeometry.string = name
+ // Check for previously color
+ let prevColor = geom.firstMaterial?.diffuse.contents as! NSColor
+ if prevColor != NSColor.grayColor() {
+ geom.firstMaterial?.diffuse.contents = NSColor.grayColor()
+ ledColorOn = false
+ }else{
+ let hueColor = CGFloat(klickedColor) / 255.0
+ geom.firstMaterial?.diffuse.contents = NSColor(calibratedHue: hueColor, saturation: 1.0, brightness: 1.0, alpha: 1.0)
+ ledColorOn = true
+ }
+ ledPressed = Int(name.intValue)
+
+ // Update the LED frame
+ var myByte: UInt8
+ if ledColorOn {
+ myByte = klickedColor
+ }else{
+ myByte = 255 // Off
+ }
+ __animations.setLEDColor(myByte, led: ledPressed)
+
+ }
+ }
+ }
+
+ /*
+ if let rootNode = self.scene?.rootNode {
+ if let cubeNode = rootNode.childNodeWithName("cubeNode", recursively: true) {
+ if let boxNode = cubeNode.childNodeWithName("myBox", recursively: true ) {
+ //anim = false
+ }
+ }
+ } */
+
+
+ //let name:NSString = result.node!.geometry!.name!
+/*
+ let myScene:SCNScene = self.scene!
+ let myRootNode:SCNNode = myScene.rootNode
+ let myTextNode:SCNNode = myRootNode.childNodeWithName("myDescr", recursively: false)!
+ let myGeometry:SCNText = myTextNode.geometry as SCNText
+*/
+
+
+
+ //let nextNode = self.scene
+ //let text = self.scene?.rootNode.childNodeWithName("myDescr", recursively: true)
+
+
+ //println(name);
+
+
+ if anim {
+
+ // highlight it
+ SCNTransaction.begin()
+ SCNTransaction.setAnimationDuration(0.2)
+
+ // on completion - unhighlight
+ SCNTransaction.setCompletionBlock() {
+ SCNTransaction.begin()
+ SCNTransaction.setAnimationDuration(0.2)
+
+ material.emission.contents = NSColor.blackColor()
+
+ SCNTransaction.commit()
+ }
+
+ material.emission.contents = NSColor.grayColor()
+
+ SCNTransaction.commit()
+
+ //myFrames.replaceBytesInRange(NSMakeRange(((myFrameCount-1)*64)+ledPressed, 1), withBytes: myByte)
+
+ }
+
+ }
+ }
+
+ super.mouseDown(theEvent)
+ }
+
+ func moveArrows(colorY: Int) {
+ // Range is from y=+15 ... -1
+ let myArrowsNode = self.scene!.rootNode.childNodeWithName("myArrows", recursively: true)
+ let myRelativePos = 16.0 * CGFloat(colorY) / 255.0
+ SCNTransaction.begin()
+ SCNTransaction.setAnimationDuration(0.5)
+ myArrowsNode?.position = SCNVector3(x:17, y: (16 - myRelativePos)-1, z:0.1)
+ SCNTransaction.commit()
+ }
+
+ func rotateCamera(var x: CGFloat, var y: CGFloat) {
+ // Save the angle for reset
+ startAngle = startAngle + y
+
+ // rotate
+ if let node = self.scene!.rootNode.childNodeWithName("cubeNode", recursively: true) {
+ node.runAction(SCNAction.rotateByX(0, y: y, z: 0, duration: 0.5))
+ }
+ //println(startAngle)
+ }
+
+ override func mouseUp(theEvent: NSEvent) {
+ // Reset the last location
+ lastMousePos.x = 0.0
+ lastMousePos.y = 0.0
+
+ super.mouseUp(theEvent)
+ }
+
+ override func mouseDragged(theEvent: NSEvent) {
+ let mousePos = theEvent.locationInWindow
+ if lastMousePos.x > 0.0 {
+ let drag = ( (lastMousePos.x - mousePos.x ) / 50 ) * -1
+ rotateCamera(0.0, y: drag)
+ lastMousePos = mousePos
+ //println(drag)
+ }
+
+ super.mouseDragged(theEvent)
+ }
+
+ override func flagsChanged(theEvent: NSEvent) {
+// println(theEvent.keyCode)
+ }
+
+ override func keyDown(theEvent: NSEvent) {
+
+ /*
+ if theEvent.modifierFlags & .CommandKeyMask != nil {
+ println("cmd pressed")
+ }
+*/
+
+
+ switch (theEvent.keyCode) {
+ case 123:
+ self.rotateCamera(0.0, y: -0.1)
+ // Left
+ break;
+ case 124:
+ self.rotateCamera(0.0, y: 0.1)
+ //self.rotateByAngle(-1.0);
+ //right
+ break;
+ case 15: // r - Key
+ // Reset the cube position
+ self.rotateCamera(0.0, y: -startAngle)
+ break;
+ case 17: // t - Key
+ // Reset the frame color on the Cube
+ //myFrames.replaceBytesInRange(NSMakeRange(myFrameCount-1, 64), withBytes: emptyFrame)
+ __animations.clearLEDColor()
+
+ // Reset the frame color in 3D
+ if let rootNode = self.scene?.rootNode {
+ if let cubeNode = rootNode.childNodeWithName("cubeNode", recursively: true) {
+ for myLED in cubeNode.childNodes {
+ if let name:NSString = myLED.name {
+ if name != "myBox" { // LED lamps
+ if let geometry: SCNGeometry = myLED.geometry {
+ if let material: SCNMaterial = geometry.firstMaterial {
+ material.diffuse.contents = NSColor.grayColor()
+ //println(name)
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ break;
+ default:
+ super.keyDown(theEvent)
+ }
+
+ println(theEvent.keyCode);
+
+
+ //super.keyDown(theEvent)
+ }
+
+}
diff --git a/Cube4Fun/src/GameViewController.swift b/Cube4Fun/src/GameViewController.swift
new file mode 100644
index 0000000..574203a
--- /dev/null
+++ b/Cube4Fun/src/GameViewController.swift
@@ -0,0 +1,230 @@
+//
+// GameViewController.swift
+// Cube4Fun
+//
+// Created by Nikolai Rinas on 27.03.15.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+import SceneKit
+import QuartzCore
+
+/*
+var myFrameCount: UInt32 = 1;
+var myMaxFrameCount: UInt32 = 1;
+var myFrames: NSMutableData = NSMutableData() // == byte[] array
+var _emptyAnimation: NSMutableDictionary = ["AnimName": "Animation1", "AnimKey": "1=anim1", "AnimDur": 1, "AnimSpeed": 500, "AnimFrames": 1, "AnimData": myFrames]
+
+let emptyFrame: [Byte] = [
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255,
+ 255,255,255,255]
+
+let _minSendDelay: NSTimeInterval = 0.200 // 200 milliseconds
+let _frameSendDelay: NSTimeInterval = 0.2 // one second
+var _playSendDelay: NSTimeInterval = 0.5 // 500 milliseconds as default
+*/
+
+var _previousUpdateTime: NSTimeInterval = NSTimeInterval()
+var _deltaTime: NSTimeInterval = NSTimeInterval()
+var _playAllFrames = false
+var _gameView: GameView = GameView();
+
+class GameViewController: NSViewController { // SCNSceneRendererDelegate
+
+ @IBOutlet weak var gameView: GameView!
+
+
+ /*
+ func renderer(aRenderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {
+ //sendFrame(time)
+ sendFrame(NSDate.timeIntervalSinceReferenceDate())
+ //println("This will be called before each frame draw")
+ }
+
+ override func viewDidLoad() {
+ self.gameView!.delegate = self
+
+ super.viewDidLoad()
+ }
+ */
+
+
+ //func sendFrame() {
+ // sendFrame(NSDate.timeIntervalSinceReferenceDate())
+ //}
+
+ /*
+ func sendFrame(time: NSTimeInterval) {
+ //println(time)
+
+ if (_previousUpdateTime == 0.0) {
+ _previousUpdateTime = time;
+ }
+ _deltaTime = time - _previousUpdateTime;
+
+ //var ms = Int((time % 1) * 1000)
+ if ( _playAllFrames ) {
+ if ( _deltaTime >= __animations.animationSpeedFloat() ){
+ if (__animations.getAnimationFrameID() >= __animations.getAnimationFrameCount()) {
+ self.gameView!.firstButtonPressed()
+ }else{
+ self.gameView!.nextButtonPressed()
+ }
+ CubeNetworkObj.updateFrame(__animations.getAnimDataSelected(), count: UInt32(__animations.getAnimationFrameID()))
+ _previousUpdateTime = time;
+ }
+ }else{
+ if ( _deltaTime >= __animations.getMinSendDelay() ) {
+ CubeNetworkObj.updateFrame(__animations.getAnimDataSelected(), count: UInt32(__animations.getAnimationFrameID()))
+ //println("SendFrame: \(_deltaTime)")
+ _previousUpdateTime = time;
+ }
+ }
+ //CubeNetworkObj.updateFrame(UnsafePointer(myFrames.bytes), count: myFrameCount)
+ }
+
+*/
+
+ override func awakeFromNib(){
+
+ _gameView = gameView;
+ //NSTimer.scheduledTimerWithTimeInterval(_frameSendDelay, invocation: CubeNetworkObj.initObjects(), repeats: true)
+// CubeNetworkObj.initObjects();
+
+ // Init first frame
+
+// myFrames = NSMutableData(bytes: emptyFrame, length: 64)
+// myFrameCount = 1
+ // Open connection to the LED cube
+ let established = CubeNetworkObj.openConnection(__prefData.ipAddr(), port: UInt32(__prefData.portNR()))
+ if established {
+ println("connection established")
+ }else{
+ println("connection failed")
+ }
+ __animations.sendFrame()
+
+ // Fallback timer if nothing render at the moment
+ // NSTimer.scheduledTimerWithTimeInterval(__animations.getMinSendDelay(), target: self, selector: Selector("sendFrame"), userInfo: nil, repeats: true)
+
+
+
+
+ // create a new scene
+ //let scene = SCNScene(named: "art.scnassets/ship.dae")!
+ let scene = PrimitivesScene();
+
+
+ // create and add a camera to the scene
+ let camera = SCNCamera()
+ camera.usesOrthographicProjection = true
+ camera.orthographicScale = 15
+ camera.zNear = 0
+ camera.zFar = 100
+ let cameraNode = SCNNode()
+ cameraNode.camera = camera
+ cameraNode.name = "myCamera"
+ scene.rootNode.addChildNode(cameraNode)
+
+ // place the camera
+ var newAngle = (CGFloat)(20.0)*(CGFloat)(M_PI)/180.0
+ //newAngle += currentAngle
+
+// cameraNode.transform = SCNMatrix4MakeRotation(-0.5, 0, 0, 1)
+
+ cameraNode.transform = SCNMatrix4MakeRotation(newAngle, 0, 1, 0)
+ cameraNode.transform = SCNMatrix4MakeRotation(-0.4, 1, 0, 0)
+ cameraNode.position = SCNVector3(x: 0, y: 13, z: 30)
+ //cameraNode.eulerAngles = SCNVector3(x: 1.0, y: 0.0, z: 0.0)
+
+
+ /*
+ let camera = SCNCamera()
+ camera.usesOrthographicProjection = true
+ camera.orthographicScale = 9
+ camera.zNear = 0
+ camera.zFar = 100
+ let cameraNode = SCNNode()
+ cameraNode.position = SCNVector3(x: 0, y: 0, z: 20)
+ cameraNode.camera = camera
+ let cameraOrbit = SCNNode()
+ cameraOrbit.name = "myCamera"
+ cameraOrbit.addChildNode(cameraNode)
+ scene.rootNode.addChildNode(cameraOrbit)
+*/
+
+ // create and add a light to the scene
+ let lightNode = SCNNode()
+ lightNode.light = SCNLight()
+ lightNode.light!.type = SCNLightTypeDirectional
+ lightNode.light!.color = NSColor.grayColor()
+ lightNode.position = SCNVector3(x: 20, y: 40, z: 20)
+ scene.rootNode.addChildNode(lightNode)
+
+ // create and add an ambient light to the scene
+ let ambientLightNode = SCNNode()
+ ambientLightNode.light = SCNLight()
+ ambientLightNode.light!.type = SCNLightTypeAmbient
+ ambientLightNode.light!.color = NSColor.darkGrayColor()
+ scene.rootNode.addChildNode(ambientLightNode)
+
+
+ // Background image
+ scene.background.contents = NSImage(named: "Background.jpg")
+
+
+ /*
+ // retrieve the ship node
+ let ship = scene.rootNode.childNodeWithName("ship", recursively: true)!
+
+ // animate the 3d object
+ let animation = CABasicAnimation(keyPath: "rotation")
+ animation.toValue = NSValue(SCNVector4: SCNVector4(x: CGFloat(0), y: CGFloat(1), z: CGFloat(0), w: CGFloat(M_PI)*2))
+ animation.duration = 3
+ animation.repeatCount = MAXFLOAT //repeat forever
+ ship.addAnimation(animation, forKey: nil)
+ */
+
+ scene.paused = false
+
+ // set the scene to the view
+ self.gameView!.scene = scene
+
+
+ // allows the user to manipulate the camera
+ //self.gameView!.allowsCameraControl = true
+
+ // show statistics such as fps and timing information
+ //self.gameView!.showsStatistics = true
+
+ // configure the view
+ self.gameView!.backgroundColor = NSColor.blackColor()
+ }
+
+}
diff --git a/Cube4Fun/src/ObjCtoCPlusPlus.h b/Cube4Fun/src/ObjCtoCPlusPlus.h
new file mode 100755
index 0000000..59517f0
--- /dev/null
+++ b/Cube4Fun/src/ObjCtoCPlusPlus.h
@@ -0,0 +1,29 @@
+//
+// ObjCtoCPlusPlus.h
+//
+// Created by Nikolai Rinas on 02/02/2015.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+#import
+
+@interface CubeNetworkObj : NSObject
++ (void) updateFrame: (const unsigned char *) frameSequence count: (UInt32) frameCount;
++ (void) sendBytes: (const unsigned char *) byteBuffer count: (u_int32_t) byteLength;
+//+ (void) initObjects;
++ (bool) openConnection: (const char *) ipAddress port: (UInt32) port;
++ (void) closeConnection;
++ (bool) connected;
+@end
\ No newline at end of file
diff --git a/Cube4Fun/src/ObjCtoCPlusPlus.mm b/Cube4Fun/src/ObjCtoCPlusPlus.mm
new file mode 100755
index 0000000..cfdd196
--- /dev/null
+++ b/Cube4Fun/src/ObjCtoCPlusPlus.mm
@@ -0,0 +1,53 @@
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+#import "ObjCtoCPlusPlus.h"
+
+#import "CubeNetwork.h"
+
+
+@implementation CubeNetworkObj
+
+/*
++ (void) initObjects
+{
+ CubeNetwork::initObjects();
+}
+ */
++ (void) updateFrame: (const unsigned char *) frameSequence count: (UInt32) frameCount
+{
+ CubeNetwork::updateFrame(frameSequence, frameCount);
+}
++ (void) sendBytes: (const unsigned char *) byteBuffer count: (u_int32_t) byteLength
+{
+ CubeNetwork::sendBytes(byteBuffer, byteLength);
+}
+//+ (void) openConnection
++ (bool) openConnection: (const char *) ipAddress port: (UInt32) port
+{
+ bool success = false;
+ success = CubeNetwork::openConnection(ipAddress, port);
+ return success;
+}
++ (void) closeConnection
+{
+ CubeNetwork::closeConnection();
+}
+
++ (bool) connected
+{
+ return CubeNetwork::connected();
+}
+
+@end
\ No newline at end of file
diff --git a/Cube4Fun/src/Preferences.swift b/Cube4Fun/src/Preferences.swift
new file mode 100644
index 0000000..164ce65
--- /dev/null
+++ b/Cube4Fun/src/Preferences.swift
@@ -0,0 +1,77 @@
+//
+// Preferences.swift
+// Cube4Fun
+//
+// Created by Nikolai Rinas on 18.04.15.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+import Foundation
+
+class Preferences: NSObject {
+
+ let _myPrefs: NSUserDefaults = NSUserDefaults()
+ var _myIPAddr: String = String()
+ var _myPortNr: Int = Int()
+
+ let ipaddr_txt: String = "IPADDR"
+ let portnr_txt: String = "PORTNR"
+ // ipAddr
+
+
+ override init() {
+ super.init()
+
+ // Load defaults
+ self.loadFile()
+ }
+
+ func loadFile() {
+ // Load ip address
+ if let myIPAddr: String = _myPrefs.stringForKey(ipaddr_txt) {
+ _myIPAddr = myIPAddr
+ }
+ // Load custom port
+ let myPort: Int = _myPrefs.integerForKey(portnr_txt)
+ if myPort > 0 {
+ _myPortNr = myPort
+ }
+ }
+
+ func saveFile() {
+ // Save ip address
+ _myPrefs.setObject(_myIPAddr, forKey: ipaddr_txt)
+ // Save port number
+ _myPrefs.setInteger(_myPortNr, forKey: portnr_txt)
+ }
+
+ func ipAddr() -> (String) {
+ return _myIPAddr
+ }
+
+ func setIPAddr(ipAddr: String) {
+ _myIPAddr = ipAddr
+ self.saveFile()
+ }
+
+ func portNR() -> (Int) {
+ return _myPortNr
+ }
+
+ func setPortNr(portNr: Int) {
+ _myPortNr = portNr
+ self.saveFile()
+ }
+}
\ No newline at end of file
diff --git a/Cube4Fun/src/PrimitivesScene.swift b/Cube4Fun/src/PrimitivesScene.swift
new file mode 100644
index 0000000..2c50b21
--- /dev/null
+++ b/Cube4Fun/src/PrimitivesScene.swift
@@ -0,0 +1,283 @@
+//
+// PrimitivesScene.swift
+// Cube4Fun
+//
+// Created by Nikolai Rinas on 27.03.15.
+// Copyright (c) 2015 Nikolai Rinas. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+
+import Cocoa
+import SceneKit
+import QuartzCore
+
+let debugOn = false
+let animRun = false
+
+class PrimitivesScene: SCNScene {
+
+ func createPlayback() {
+ // Play - Button
+ let playImage = SCNPlane(width: 2.2, height: 2.2)
+ playImage.firstMaterial?.diffuse.contents = NSImage(named: "media-playback-start-5.png")
+ let playImageNode = SCNNode(geometry: playImage)
+ playImageNode.name = "myPlayButton"
+ playImageNode.position = SCNVector3(x:0, y:14, z:0)
+ self.rootNode.addChildNode(playImageNode)
+
+ // Pause - Button
+ let pauseImage = SCNPlane(width: 2.5, height: 2.5)
+ pauseImage.firstMaterial?.diffuse.contents = NSImage(named: "media-playback-pause-5.png")
+ let pauseImageNode = SCNNode(geometry: pauseImage)
+ pauseImageNode.name = "myPauseButton"
+ pauseImageNode.position = SCNVector3(x:0, y:14, z:0)
+ pauseImageNode.hidden = true
+ if __animations.getAnimationFrameID() == 1 && __animations.getAnimationFrameCount() == 1 {
+ pauseImageNode.hidden = true
+ }
+ self.rootNode.addChildNode(pauseImageNode)
+
+ // NextFrame - Button
+ let nextFrameImage = SCNPlane(width: 2.0, height: 2.0)
+ nextFrameImage.firstMaterial?.diffuse.contents = NSImage(named: "media-seek-forward-5.png")
+ let nextFrameImageNode = SCNNode(geometry: nextFrameImage)
+ nextFrameImageNode.name = "myNextFrameButton"
+ nextFrameImageNode.position = SCNVector3(x:2, y:14, z:0)
+ if __animations.getAnimationFrameID() == 1 && __animations.getAnimationFrameCount() == 1 {
+ nextFrameImageNode.hidden = true
+ }
+ self.rootNode.addChildNode(nextFrameImageNode)
+
+ // PrevFrame - Button
+ let prevFrameImage = SCNPlane(width: 2.0, height: 2.0)
+ prevFrameImage.firstMaterial?.diffuse.contents = NSImage(named: "media-seek-backward-5.png")
+ let prevFrameImageNode = SCNNode(geometry: prevFrameImage)
+ prevFrameImageNode.name = "myPrevFrameButton"
+ prevFrameImageNode.position = SCNVector3(x:-2, y:14, z:0)
+ if __animations.getAnimationFrameID() == 1 {
+ prevFrameImageNode.hidden = true
+ }
+ self.rootNode.addChildNode(prevFrameImageNode)
+
+ // StartFrame - Button
+ let startFrameImage = SCNPlane(width: 2.0, height: 2.0)
+ startFrameImage.firstMaterial?.diffuse.contents = NSImage(named: "media-skip-backward-5.png")
+ let startFrameImageNode = SCNNode(geometry: startFrameImage)
+ startFrameImageNode.name = "myStartFrameButton"
+ startFrameImageNode.position = SCNVector3(x:-5, y:14, z:0)
+ if __animations.getAnimationFrameID() == 1 {
+ startFrameImageNode.hidden = true
+ }
+ self.rootNode.addChildNode(startFrameImageNode)
+
+ // LastFrame - Button
+ let lastFrameImage = SCNPlane(width: 2.0, height: 2.0)
+ lastFrameImage.firstMaterial?.diffuse.contents = NSImage(named: "media-skip-forward-5.png")
+ let lastFrameImageNode = SCNNode(geometry: lastFrameImage)
+ lastFrameImageNode.name = "myLastFrameButton"
+ lastFrameImageNode.position = SCNVector3(x:5, y:14, z:0)
+ if __animations.getAnimationFrameID() == __animations.getAnimationFrameCount() {
+ lastFrameImageNode.hidden = true
+ }
+ self.rootNode.addChildNode(lastFrameImageNode)
+
+ }
+
+ func createSpeedButtons() {
+ // Frame
+ let textSpeed = SCNText(string: "Speed: \(__animations.animationSpeedInt()) ms", extrusionDepth: 0)
+ textSpeed.font = NSFont(name: "Arial", size: 1.2)
+ let textSpeedNode = SCNNode(geometry: textSpeed)
+ textSpeedNode.name = "mySpeedText"
+ textSpeedNode.position = SCNVector3(x:-20.0 , y: 9.7, z: 0.0)
+ self.rootNode.addChildNode(textSpeedNode)
+
+ // SpeedUp - Button
+ let plusSpeedImage = SCNPlane(width: 1.7, height: 1.7)
+ plusSpeedImage.firstMaterial?.diffuse.contents = NSImage(named: "list-add-2.png")
+ let plusSpeedImageNode = SCNNode(geometry: plusSpeedImage)
+ plusSpeedImageNode.name = "myPlusSpeedButton"
+ plusSpeedImageNode.position = SCNVector3(x:-16.5, y:8, z:0)
+ self.rootNode.addChildNode(plusSpeedImageNode)
+
+ // SpeedDown - Button
+ let minusSpeedImage = SCNPlane(width: 1.7, height: 1.7)
+ minusSpeedImage.firstMaterial?.diffuse.contents = NSImage(named: "list-remove-2.png")
+ let minusSpeedImageNode = SCNNode(geometry: minusSpeedImage)
+ minusSpeedImageNode.name = "myMinusSpeedButton"
+ minusSpeedImageNode.position = SCNVector3(x:-18.7, y:8, z:0)
+ self.rootNode.addChildNode(minusSpeedImageNode)
+ }
+
+ func createFrameButtons() {
+ let textFrame = SCNText(string: "Frame: \(__animations.getAnimationFrameID())/\(__animations.getAnimationFrameCount())", extrusionDepth: 0)
+ textFrame.font = NSFont(name: "Arial", size: 1.2)
+ let textFrameNode = SCNNode(geometry: textFrame)
+ textFrameNode.name = "myFrameText"
+ textFrameNode.position = SCNVector3(x:-20.0 , y: 13.7, z: 0.0)
+ self.rootNode.addChildNode(textFrameNode)
+
+ // AddFrame - Button
+ let addFrameImage = SCNPlane(width: 1.7, height: 1.7)
+ addFrameImage.firstMaterial?.diffuse.contents = NSImage(named: "list-add-2.png")
+ let addFrameImageNode = SCNNode(geometry: addFrameImage)
+ addFrameImageNode.name = "myAddFrameButton"
+ addFrameImageNode.position = SCNVector3(x:-16.5, y:12, z:0)
+ self.rootNode.addChildNode(addFrameImageNode)
+
+ // DeleteFrame - Button
+ let delFrameImage = SCNPlane(width: 1.7, height: 1.7)
+ delFrameImage.firstMaterial?.diffuse.contents = NSImage(named: "list-remove-2.png")
+ let delFrameImageNode = SCNNode(geometry: delFrameImage)
+ delFrameImageNode.name = "myDelFrameButton"
+ delFrameImageNode.position = SCNVector3(x:-18.7, y:12, z:0)
+ // for first frame, there is nothing to delete
+ if ( __animations.getAnimationFrameID() == 1 ) {
+ delFrameImageNode.hidden = true
+ }
+ self.rootNode.addChildNode(delFrameImageNode)
+ }
+
+ func createOpenAnimations() {
+ let textAnimations = SCNText(string: "List Animations", extrusionDepth: 0)
+ textAnimations.font = NSFont(name: "Arial", size: 1.2)
+ let textAnimationsNode = SCNNode(geometry: textAnimations)
+ textAnimationsNode.name = "myAnimationsText"
+ textAnimationsNode.position = SCNVector3(x:-20.0 , y: 5.7, z: 0.0)
+ self.rootNode.addChildNode(textAnimationsNode)
+
+ // Manage Animations - Button
+ let mngAnimationsImage = SCNPlane(width: 1.7, height: 1.7)
+ mngAnimationsImage.firstMaterial?.diffuse.contents = NSImage(named: "view-sidetree.png")
+ let mngAnimationsImageNode = SCNNode(geometry: mngAnimationsImage)
+ mngAnimationsImageNode.name = "myMngAnimationsButton"
+ mngAnimationsImageNode.position = SCNVector3(x:-16.5, y:4, z:0)
+ self.rootNode.addChildNode(mngAnimationsImageNode)
+ }
+
+ override init() {
+ super.init()
+
+ var radius:CGFloat = 1.0
+
+ let yCount = 4
+ let zCount = 4
+ let xCount = 4
+ var myIndex = 0
+
+ let spaceBetweenLEDs:CGFloat = 4.0
+ let edgePosX:CGFloat = CGFloat(xCount-1) * spaceBetweenLEDs * -1 / 2
+ let edgePosY:CGFloat = CGFloat(yCount-1) * spaceBetweenLEDs * -1 / 2
+ let edgePosZ:CGFloat = CGFloat(zCount-1) * spaceBetweenLEDs * -1 / 2
+ let boxSizeX:CGFloat = CGFloat(xCount-1) * spaceBetweenLEDs + 2 * radius
+ let boxSizeZ:CGFloat = CGFloat(zCount-1) * spaceBetweenLEDs + 2 * radius
+ let boxPosY:CGFloat = (CGFloat(yCount-1) * spaceBetweenLEDs / 2) + radius + 0.5
+
+
+ // ID for the LED
+ let text = SCNText(string: "Klick", extrusionDepth: 0)
+ text.font = NSFont(name: "Arial", size: 1.5)
+ let textNode = SCNNode(geometry: text)
+ textNode.name = "myDescr"
+ if ( debugOn ) {
+ textNode.position = SCNVector3(x:-20.0 , y: -14.0, z: 0.0)
+ }else{
+ textNode.position = SCNVector3(x:-20.0 , y: -24.0, z: 0.0)
+ }
+ self.rootNode.addChildNode(textNode)
+
+ // Frame
+ createFrameButtons()
+
+ // Action Buttons
+ createPlayback()
+
+ // Speed Buttons
+ createSpeedButtons()
+
+ // Open Animation Button
+ createOpenAnimations()
+
+ // color picker
+ let colorBar = SCNPlane(width: 3, height: 16)
+ colorBar.firstMaterial?.diffuse.contents = NSImage(named: "Gradient2.png")
+ let colorBarNode = SCNNode(geometry: colorBar)
+ colorBarNode.name = "myColorBar"
+ colorBarNode.position = SCNVector3(x: 17, y: 7, z:0.0)
+ self.rootNode.addChildNode(colorBarNode)
+
+ // Arrows
+ let arrowImage = SCNPlane(width: 3, height: 2.0)
+ arrowImage.firstMaterial?.diffuse.contents = NSImage(named: "Arrows.png")
+ let arrowImageNode = SCNNode(geometry: arrowImage)
+ arrowImageNode.name = "myArrows"
+ arrowImageNode.position = SCNVector3(x:17, y:15, z:0.1)
+ self.rootNode.addChildNode(arrowImageNode)
+
+
+ // All movable objects
+ let cubeNode = SCNNode()
+ cubeNode.name = "cubeNode"
+
+ let box = SCNBox(width: boxSizeX, height: 1.0, length: boxSizeZ, chamferRadius: 0.1)
+ box.firstMaterial?.diffuse.contents = NSColor.whiteColor()
+ let boxNode = SCNNode(geometry: box)
+ boxNode.name = "myBox"
+ boxNode.position = SCNVector3(x:0.0 , y: -boxPosY, z: 0.0)
+ cubeNode.addChildNode(boxNode)
+
+
+ var y:CGFloat = edgePosY
+ for row in 0..