-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathViewportArrayApp.cpp
162 lines (139 loc) · 4.89 KB
/
ViewportArrayApp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/CameraUi.h"
#include "cinder/Rand.h"
using namespace ci;
using namespace ci::app;
using namespace std;
class ViewportArrayApp : public App {
public:
void setup() override;
void resize() override;
void update() override;
void draw() override;
void mouseDown( MouseEvent event ) override;
void mouseDrag( MouseEvent event ) override;
void mouseUp( MouseEvent event ) override;
void mouseWheel( MouseEvent event ) override;
void updateViewports();
gl::FboRef mFbo;
gl::BatchRef mTeapot;
array<CameraPersp,4> mCameras;
CameraUi mCameraUi;
vector<Rectf> mViewports;
};
void ViewportArrayApp::setup()
{
// create the teapot batch with our multicast geometry shader
auto shForm = gl::GlslProg::Format().vertex( loadAsset( "shader.vert" ) ).geometry( loadAsset( "shader.geom" ) ).fragment( loadAsset( "shader.frag" ) );
auto shader = gl::GlslProg::create( shForm );
auto geom = geom::Teapot().subdivisions(10) >> geom::ColorFromAttrib(geom::Attrib::NORMAL, (const std::function<Colorf(vec3)>&) [](vec3 v){ return Colorf(v.x, v.y, v.z); });
mTeapot = gl::Batch::create( geom, shader );
// create 4 cameras randomly spread around the teapot
randSeed( 12345 );
for( auto &camera : mCameras ) {
camera = CameraPersp( getWindowWidth(), getWindowHeight(), 50, 0.1f, 100.0f );
camera.lookAt( randVec3() * randFloat( 1.5f, 3.0f ), vec3( 0.0f, 0.35f, 0.0f ) );
}
}
void ViewportArrayApp::resize()
{
// update each aspect/resolution dependant objects
mFbo = gl::Fbo::create( getWindowWidth(), getWindowHeight(), gl::Fbo::Format().samples( 16 ) );
mCameraUi.setWindowSize( getWindowSize() / 2 );
for( auto &camera : mCameras ) {
camera.setAspectRatio( getWindowAspectRatio() );
}
// and recreate/upload each viewports
updateViewports();
}
void ViewportArrayApp::update()
{
// bind the fbo and enable depth testing
gl::ScopedFramebuffer scopedFbo( mFbo );
gl::ScopedDepth scopedDepthTest( true );
// clear our fbo
gl::clear( Color( 0, 0, 0 ) );
// create an array with the different cameras matrices
vector<mat4> matrices;
for( auto cam : mCameras ) {
matrices.push_back( cam.getProjectionMatrix() * cam.getViewMatrix() );
}
// and send it to the shader
mTeapot->getGlslProg()->uniform( "uMatrices", &matrices[0], mCameras.size() );
// render the teapot once (the geometry shader takes care of the rest)
mTeapot->draw();
}
void ViewportArrayApp::draw()
{
// clear the screen and set matrices
gl::clear( Color( 0, 0, 0 ) );
gl::setMatricesWindow( getWindowSize() );
// render our fbo texture
gl::draw( mFbo->getColorTexture() );
// and viewport bounds
for( auto viewport : mViewports ) {
gl::drawStrokedRect( viewport );
}
}
void ViewportArrayApp::updateViewports()
{
// update the viewport array
mViewports = {
Rectf( vec2( 0.0f, 0.0f ), vec2( getWindowCenter().x, getWindowCenter().y ) ),
Rectf( vec2( getWindowCenter().x, 0.0f ), vec2( getWindowSize().x, getWindowCenter().y ) ),
Rectf( vec2( 0.0f, getWindowCenter().y ), vec2( getWindowCenter().x, getWindowSize().y ) ),
Rectf( vec2( getWindowCenter().x, getWindowCenter().y ), vec2( getWindowSize().x, getWindowSize().y ) )
};
// transform it to a float array that opengl can understand
// the first viewport will be the main one used in the draw function
vector<float> viewportsf;
viewportsf.push_back( 0.0f );
viewportsf.push_back( 0.0f );
viewportsf.push_back( getWindowWidth() );
viewportsf.push_back( getWindowHeight() );
for( auto viewport : mViewports ) {
viewportsf.push_back( viewport.getX1() );
viewportsf.push_back( getWindowHeight() - viewport.getY2() );
viewportsf.push_back( viewport.getWidth() );
viewportsf.push_back( viewport.getHeight() );
}
// upload the viewport array
glViewportArrayv( 0, 5, &viewportsf[0] );
}
int getViewportAt( const vector<Rectf> &viewports, const ci::vec2 &position )
{
int viewport = -1;
for( size_t i = 0; i < viewports.size(); ++i ){
if( viewports[i].contains( position ) ) {
viewport = i;
break;
}
}
return viewport;
}
static int currentViewport;
void ViewportArrayApp::mouseDown( MouseEvent event )
{
int viewport = currentViewport = getViewportAt( mViewports, event.getPos() );
if( viewport != -1 ) mCameraUi.setCamera( &mCameras[viewport] );
mCameraUi.mouseDown( event );
}
void ViewportArrayApp::mouseDrag( MouseEvent event )
{
if( currentViewport != -1 ) mCameraUi.setCamera( &mCameras[currentViewport] );
mCameraUi.mouseDrag( event );
}
void ViewportArrayApp::mouseUp( MouseEvent event )
{
if( currentViewport != -1 ) mCameraUi.setCamera( &mCameras[currentViewport] );
mCameraUi.mouseUp( event );
}
void ViewportArrayApp::mouseWheel( MouseEvent event )
{
int viewport = getViewportAt( mViewports, event.getPos() );
if( viewport != -1 ) mCameraUi.setCamera( &mCameras[viewport] );
mCameraUi.mouseWheel( event );
}
CINDER_APP( ViewportArrayApp, RendererGl )