Giter Site home page Giter Site logo

cinder-bluecadetviews's Introduction

Cinder-BluecadetViews

This block presents a set of classes to build an interactive scene graph and a set of base implementations to more easily create app UIs in Cinder.

The scene graph is composed of individual views, which can have children and each have basic animatable properties like position, scale, rotation and alpha. Children inherit their parents' transformations.

In addition to nested transformations and drawing, this block connects to the text and touch blocks to provide TextView and TouchView.

To combine all pieces conveniently, this block comes with a BaseApp class that provides a basic implementation with a root view, touch manager and various utilities.

Built for and tested with Cinder v0.9.2 dev. See notes below for setup instructions.

Key Features

Scene Graph

  • Add/remove children to/from BaseViews and all its subclasses
  • Conversion from/to local/global coordinate spaces
  • Simple event system to bubble messages up the graph
  • Index management (e.g. move child to front/back)
  • Inherited transformations, alpha and tint

Touch Management

  • Support for TUIO, native touch and mouse events
  • Touch simulator for stress-testing tapping and dragging
  • Multi-touch simulator for mouse input (e.g. to scale/rotate)
  • Extendable plugin architecture (e.g. for TangibleEngine pucks or third-party gesture libraries like GestureWorks)
  • Shape-based hit detection with ability to override on a per-class basis

Core App Classes

  • Define screen layout for multi-screen matrices
  • Pan and zoom around your app using keyboard shortcuts with a minimap with touchable views
  • Central, extendable settings manager to load common and custom JSON and CLI settings like FPS, V-Sync, Screen Layout, etc.

BaseView

A basic, rectangular view with an optional size and background color that can contain children and be added as a child to other BaseViews.

  • Animatable properties: position, scale, rotation, tint, alpha, backgroundColor
  • Transform origin for rotating and scaling around a local point
  • update() and draw() loops

TouchView

  • Extends BaseView with added touch capabilities
  • Touch began, updated and ended events, overrideable protected methods and explicit signals
  • Distinction between dragging and tapping with distance and time thresholds

TextView

  • Multi-line text layout with basic inline styling support
  • HTML tags: <b>, <i>, <br>, <p>
  • Styles: fontFamily, fontStyle, fontWeight, fontSize, leadingOffset, textColor, textAlign, textTransform
  • Automatic word-wrapping and other layout modes (single line, strip line-breaks, multi-line clip, multi-line auto-wrap)
  • string and wstring support
  • Layout-caching minimizes re-calculation of layout while maintaining ability to call methods like getSize() at any time
  • Windows only, requires Cinder-BluecadetText

MaskView

  • A MaskView can use any BaseView as a mask for its child views
  • REVEAL and HIDE masked content modes (essentially stencil or knockout)
  • Uses GL stencils, so doesn't support semi-transparency, but does allow for more custom shapes than GL scissor
  • Most view subclasses can be used individually and combined as masks

SettingsManager

The SettingsManager provides an easy means to map JSON settings to app parameters, override them via command line parameters for development and load/save them to/from JSON via InterfaceGl params.

View Samples

Misc Features

Multi-Screen Support Virtual Touches & Stress Testing
Bezel compensation, debug layout, mini-map, keyboard-based panning/zooming. Built-in support to create virtual touches and stress test your app. Can also be used to simulate complex touch patterns like capacitive fiducials.
Multi-Touch Simulation Debug Info Plugin Support
Simulate multiple touches with your mouse cursor. Display view bounds, position, transform origin, type and name or id. Simulate, intercept and manipulate touches with custom plugins.

Getting Started

Clone the block and check the dependencies below to make sure you're all set to start your first project.

You can use the boilerplate below for your main application file:

#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"

#include "bluecadet/core/BaseApp.h"
#include "bluecadet/views/TouchView.h"

using namespace ci;
using namespace ci::app;
using namespace std;

using namespace bluecadet::core;
using namespace bluecadet::views;
using namespace bluecadet::touch;

class BaseAppSampleApp : public BaseApp {
public:
	static void prepareSettings(ci::app::App::Settings* settings);
	void setup() override;
	void update() override;
	void draw() override;
};

void BaseAppSampleApp::prepareSettings(ci::app::App::Settings* settings) {
	// Optional: Override the shared settings manager instance with your subclass
	SettingsManager::setInstance(myApp::MyAppSettingsManager::get());
	
	// Initialize the settings manager with the cinder app settings and the settings json
	SettingsManager::get()->setup(settings);
}

void BaseAppSampleApp::setup() {

	BaseApp::setup();

	// Optional: configure your root view
	getRootView()->setBackgroundColor(Color::gray(0.5f));

	// Sample content
	auto button = make_shared<TouchView>();
	button->setPosition(400.f, 300.f);
	button->setSize(200.f, 100.f);
	button->setBackgroundColor(Color(1, 0, 0));
	button->getSignalTapped().connect([=](...) { CI_LOG_I("Button tapped"); });
	getRootView()->addChild(button);
}

void BaseAppSampleApp::update() {
	// Optional override. BaseApp::update() will update all views.
	BaseApp::update();
}

void BaseAppSampleApp::draw() {
	// Optional override. BaseApp::draw() will draw all views.
	BaseApp::draw();
}

// Make sure to pass a reference to prepareSettings to configure the app correctly. MSAA and other render options are optional.
CINDER_APP(BaseAppSampleApp, RendererGl(RendererGl::Options().msaa(4)), BaseAppSampleApp::prepareSettings);

Tinderbox Template

To make setup easier, this block includes a template called Bluecadet App. When you open TinderBox to create a new project, select Bluecadet App from the Template dropdown at the first step:

docs/media/tinderbox-template.png

This will create a base app class and a settings manager for you. The default namespace for the settings manager is bluecadet, which you're free to change.

For maximum compatibility, you should include the OSC and TUIO blocks via copy and not as relative:

docs/media/tinderbox-includes.png

Due to a TinderBox bug, your SettingsManager subclass header will be located in Header Files in your VS project. You can simply drag it to Source Files.

Cinder Path

To support maximum compatibility across machines, we encourage you to use the provided ProjectConfig.props property sheet included in the template (at templates/BluecadetApp/ProjectConfig.props) to define your Cinder path on each computer independently.

To use it, open your Visual Studio project:

  1. Open the Property Manager view via Views > Other Windows > Property Manager
  2. Select Add Existing Property Sheet
  3. Add the ProjectConfig.props file that should be in your app's root directory now (assuming you used the Bluecadete App template to create the project)
  4. Try to build your project (it should fail)
  5. Double-click the build error that says Cinder path is not configured correctly ('C:\Users\...'). Please enter your Cinder path in 'C:\Users\...\UserConfig.props'.
  6. Enter your relative or absolute path to the Cinder root directory in <CinderDir>...</CinderDir>
  7. Rebuild

For your convenience, the template includes a .gitignore file that will automatically be copied to your project directory to ignore the auto-generated UserConfig.props file, which is machine-specific.

Custom Subviews

Out of the box, Cinder-BluecadetViews supplies the most basic types of views needed to stub out an interactive application. Eventually, you'll want to write your own BaseView subclasses that override update() or draw().

Below is a simple example:

PathView.h

#pragma once

#include "bluecadet/views/BaseView.h"

typedef std::shared_ptr<class PathView> PathViewRef;

class PathView : public bluecadet::views::BaseView {

public:
	PathView(ci::Path2d path) : mPath(path) {}
	~PathView() {}

protected:
	void update(const FrameInfo & frame) override;
	void draw() override;

	ci::Path2d mPath;
};

PathView.cpp

#include "PathView.h"

using namespace ci;
using namespace ci::app;
using namespace std;

void PathView::update(const FrameInfo & frame) {
	// update your view on each frame if you'd like
	// no need to call base view implementation.
	// FrameInfo contains the time since the previous
	// update call (deltaTime) and the time the app
	// has been running (absoluteTime).
}
void PathView::draw() {
	// no need to call base-view implementation
	// unless you want to draw a solid rect of
	// getSize() and getBackgroundColor()
	// bluecadet::views::BaseView::draw();
	
	// you could set the color to the current background color
	// but by default getTint() and getAlpha() are used
	// gl::ScopedColor color(getBackgroundColor());
	
	// this will draw the path using the current color, which
	// defaults to getDrawColor() (combination of tint and alpha)
	gl::draw(mPath);
}

Dependencies

Notes

Version 1.7.0

Built for Cinder v0.9.2 dev and Cinder v0.9.1. Samples require VS 2015 v140 toolset, but tested with VS 2013 v120 as well.

Cinder setup instructions:

# Cinder dev
git clone --depth 1 --recursive https://github.com/cinder/Cinder.git

# Cinder 0.9.1 stable
# git clone -b v0.9.1 --depth 1 --recursive https://github.com/cinder/Cinder.git

# Bluecadet blocks + dependencies
cd Cinder/blocks
git clone [email protected]:bluecadet/Cinder-BluecadetText.git
git clone [email protected]:bluecadet/Cinder-BluecadetViews.git

cinder-bluecadetviews's People

Contributors

adielfernandez avatar benjaminbojko avatar bluecadetinstallations avatar claytercek avatar kevinzak avatar mattfelsen avatar shi-weili avatar swiley avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cinder-bluecadetviews's Issues

Add support for OS X

It looks like the only thing preventing OS X support at the moment is the TextView, which we could just disable via pre-compiler statements for now. High priority for FastCo and Lightmare days, so I'll look into this asap.

CC @peterchappy

TouchManager : set app size for gesture plugin

Ran into an issue when I was adding GW into CT - the gesture event positions were being based off the size of the window instead of the app size.

I think we want to add something like this in BaseApp.cpp setup(), so that when the plugin is initialized it knows what the true app size is (current order of calls sets it to the window size).

// Set app size of touch manager (for gesture plugins)
touch::TouchManager::getInstance()->setAppSize(ScreenLayout::getInstance()->getAppSize());

and in TouchManager.h
void setAppSize(const ci::vec2& appSize) { mAppSize = appSize; }

I tried to implement it in the sample (it's working in the project I have going) - but when there is no appSettings.json the BaseApp::setup() call for ScreenLayout::getInstance()->getDisplayWidth() is returning 1857 (I think it should be returning 1080).

This is where I left off - just wanted to track these notes here as I don't have time to address it at the moment.

Add support to bake in transform origin

The transform origin currently affects how a view si dran. When changing the origin, the view will get re-positioned. There are some scenarios where we'd want to apply the transform origin back to the position and/or scale/rotation. @Swiley has a first stab at this in issue #35 and it would be great to expand that to support rotation.

Extract ScreenLayout transforms into independent camera class

ScreenLayout currently both defines the layout handles zooming and panning. The zooming and panning and the resulting transformations should happen in a separate class. This may resolve some naming confusions and make it easier to implement a separate MiniMap class or feature.

More readme edits for PathView example

A couple things that I got a bit hung up on yesterday..

  • add typedef std::shared_ptr<class PathView> PathViewRef to header
  • add bluecadet::views namespace to PathView (not sure if this is necessary, but I couldn't compile with my own subviews without this)

Centering in TextView - bug?

I thought we could set the max width and set text align to center, but that wasn't working for me. The textview was telling me it was centered and the max width was 5000, but the text was still showing left.

mTitle->setup("Test title", "general.appTitle", true, 5000.0f);
styles
2016-07-26_0928

workaround for now is to set the position to center it
@kevinzak @benjaminbojko @steinbergh @peterchappy anyone else having this issue? am I doing something out of order?

Timeline bug - possibly related to mHasInvalidTransforms

@kevinzak reported this problem yesterday, where a timeline was not getting completed if the duration was less than .5ish. @benjaminbojko also has a scenario where the timeline was weird.

I'm working with something similar now where from setup I was animating a view's position - but it wouldn't animate unless I zoomed out of the screen first. I think this is being caused by the mDirtyTransform flag not being set correctly.

Couple things I noticed. In NASM, updateTransform clears the invalid flag to TRUE,
https://github.com/bluecadet/nasm-wall/blob/develop/MediaWall/blocks/Touch/src/core/BaseView.cpp#L281
but in our new baseView it clears it to FALSE
https://github.com/bluecadet/Cinder-BluecadetViews/blob/develop/src/BaseView.cpp#L314

I think the second makes more sense. Or the variable names are tricking me. I'm not sure.

To get it to work then, I just removed the mHasInvalidTransforms = false; at the end of the drawScene(). Not sure that's the best approach, wanted to get your take @benjaminbojko

Simplify TouchView size and hit detection

  • Support for hit path
  • Support for simple size
  • Initialize with default size; hit path as specialization
  • When hit path is set, it should overwrite the current size
  • Implement setSize() for when path exists (does it overwrite path? does it scale the path?)
  • Implement getSize() for when path exists

LineView color doesn't take parent alpha animations

  • see if we can use background color instead of introducing a new line color property
  • test that the draw isn't overriding and confirm the color multiplying is happening with the parent (in the draw function of LineView)
  • play out the idea of treating this similar to a rectangle view (maybe auto setting transform origin to line based on line width) and keeping the layout of how we would treat a line (what is intuitive for starting/ending a line) without having to call gl::drawLine (this might be a terrible idea)

Question: Merge Views + Touch Blocks?

It may be controversial to pose this question now that we have running projects using both blocks, but I'm proposing to merge the Views and Touch blocks. The main reason is that they are just so tightly coupled (not inherently bad) that making changes in one block most often results in changes in the other.

Additionally, the Touch block really doesn't serve a purpose w/o the Views block. I've found myself in a few situations where I fixed something in Views and then had to do two separate pull requests in both repos or just simply forgot to update and push changes from one or the other block.

What I would like to do:

  1. Migrate all Cinder-BluecadetTouch source files and samples to CinderBluecadetViews
  2. Migrate all classes and types from bluecadet::touch to bluecadet::views (debatable, but given the fact that we won't have a Touch block I thought we shouldn't pack files into a "hidden" namespace)
  3. Delete/archive the Cinder-BluecadetTouch repository

That's really it. Please let me know what you think.

TouchView : canAcceptTouch/isTouchEnabled question

Super minor (I think), but is there a reason can accept touch doesn't just also check isTouchEnabled?

    bool TouchView::canAcceptTouch() const {
        return mMultiTouchEnabled || mObjectTouchIDs.empty();
    }

It seems the only place that isTouchEnabled() and canAcceptTouch() is used in the blocks are in this:

if (obj && (!obj->isTouchEnabled() || !obj->canAcceptTouch())) {
        // Don't check for touches in this view or in children if untouchable
        return nullptr;
    }

It seems like canAcceptTouch should also take into account if the touch is enabled.

Scenario:
I disable touch on a view, but enable multi touch. I don't think setting multi touch enabled also enables mTouchEnabled. Therefore, if I call canAcceptTouch() on a view, it would return true, though touch is technically disabled.

resetAllChildAnimations()

Is there any reason why we wouldn't want the option to easily reset all child animations? I was having an animation bug because I was being dumb and thought that resetAnimation() would reset all the child animations too.

Suggested docs additions/modifications

  • show example of using std::bind instead of lambdas for signal callbacks
  • example of event dispatch system - both dispatching & receiving
  • note on subclassing BaseViews says you'll override update or draw, but it's just as likely to not override and instead only manage child views via callbacks (child tapped, animate this, etc.). Update docs to reflect?
  • keyboard shortcuts used

Screenlayout view doesn't draw

This is a singleton, even if we add an instance as a child to the rootView, it's draw doesn't get called unless we explicitly add to the BaseApp class
ScreenLayoutView::getInstance()->draw();

This kills the point of adding it as a child. So we could just do it manually in BaseApp like this, or we could create a different type of view that would use the ScreenLayoutView information but could be added to the BaseApp like normal view.

thoughts @benjaminbojko ? am I missing something?

Ellipse views aren't smooth

for the nasm ring shader we had to smoothStep the edges to make it look nicer, suspicious we'll need that here as well

Question: Rename color to tint?

BaseView has a mColor property and getColor()/setColor() accessors. I feel like that name becomes a little confusing once we start subclassing. For example, TextView has both mTextColor and mColor. Both have an effect on how text color is rendered, but mColor takes precedence.

Essentially mColor simply gets multiplied with whatever happens in BaseView::draw(). So if the TextView renders white text and mColor is set to red, the text will become red because:

r = 1.0 * 1.0; // 1
g = 0 * 0; // 0
b = 0 * 0; // 0

If mColor is blue and mTextColor is red, then we get black text:

r = 1.0 * 0; // 0
g = 0 * 1.0; // 0
b = 0 * 0; // 0

Long story short, to me that's more of a tint than a general color. Color could mean so many different things. Thoughts?

Inlining LineView::setup() causes error

Severity Code Description Project File Line Suppression State
Error LNK2001 unresolved external symbol "public: void __cdecl bluecadet::views::LineView::setup(struct glm::tvec2 const &,class cinder::ColorAT const &,float)" (?setup@LineView@views@bluecadet@@QEAAXAEBU?$tvec2@M$0A@@glm@@AEBV?$ColorAT@M@cinder@@M@Z) ConspiracyTimeline C:\Users\Stacey\Documents\frameworks\Cinder\MoAR-CT\ConspiracyTimeline\vc2013\TimelineController.obj 1

Create App boilerplate

People keep running into common pitfalls. Perhaps a shared bluecadet::BaseApp that extends ci::App could help tie everything together. It could:

  • Provide a root view
  • Initialize the touch manager with Mouse and Tuio drivers (could be generalized via a method to override or bool flags)
  • Update the touch manager
  • Update the scene graph
  • Draw the scene graph

BaseView invalidate() - use bit flags instead of booleans

@benjaminbojko's idea In reference to BaseView's :
inline void invalidate(const bool transforms, const bool content);

"One idea I had just to keep for the future potentially was to use bit flags instead of booleans. That way we could add up to 32 options to invalidate and sub-classes could add their own. E.g. the FboView and TextView could use the same method."

getScaledSize()

Would it be possible to add a getScaledSize() to the BaseView.h? I'm finding that I'm doing a lot of
exampleView->getWidth() * exampleView->getScale().value().x What do you guys think?

Small git-related cleanup in readme

A couple small things/suggestions in the readme:

  • use https instead of ssh for clone links (I got permission denied errors with ssh)
  • --recursive does a submodule --init when cloning, so the latter line is redundant/unncessary
  • do a shallow clone with --depth 1, which saves about 250MB of space (~800 vs 550MB)
  • clone the specific branch/tag directly instead using -b v0.9.1

For reference, this line address all the above issues:

git clone -b v0.9.1 --depth 1 --recursive https://github.com/cinder/Cinder.git

Create generic FboView

  • Size property
  • Format property
  • Figure out how to automatically redraw into Fbo when subviews change
  • Render contents of subviews in draw()/drawScene()

Implement get/set size for TextView

  • Figure out how to bring together both StyledTextLayout::getSize() and BaseView::getSize()
  • Implement/override setSize() (does it set the max size? Does it define a fixed size for the resulting texture? Should it just spit out a warning for now that this method doesn't do anything for TextView?

Should changing scale update position?

Ran into this a few times lately where people are updating scale and trying to position things based on this change - but the position of the view still returns what it was before the scale changes. Just wanted to start it as an idea there

@benjaminbojko

Add actual dragging support

Currently TouchView only supports recognition of moving touches vs taps, but doesn't actually support dragging a view around. It's easy enough to do with:

setGlobalPosition(event.globalPosition - mInitialGlobalTouchPos + mInitialGlobalPosWhenTouched);

Added bonus: allow dragging on x and y axis` independently.

Add support for animatable size property

This is tricky and not implemented yet because some views rely on setSize() to set internal flags for the next update run to stay efficient with resizing/recalculating layouts (e.g. TextView). We could do a check on update to see if the size has changed via an animation (since this won't call setSize()) or we could add a method that specifically allows us to animate size (but this would introduce a new paradigm).

Update FBO View

Problem :
Unexpected transparency issues with some children of the FBO. Some images were showing the image below them through their shape, some fonts were getting oddly blurry

Found a workaround here, but then lines were jagged
http://stackoverflow.com/questions/2171085/opengl-blending-with-previous-contents-of-framebuffer

For the jagged lines, I changed the default format in our FBO view

gl::Fbo::Format format;
format.setSamples(4); // enable 4x MSAA
format.setCoverageSamples(8); // a combination which creates the "CSAA 8x" mode

setFboFormat(format);

Some research
https://forum.libcinder.org/topic/transparency-and-halos-in-fbos
https://libcinder.org/docs/guides/gl/fbo/index.html

Testing this out on CT, will push up a PR to the block when I make sure it's fully tested

@peterchappy just a heads up, since you're using an FBO view as well now

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.