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..