/usr/lib/Wt/examples/webgl/PaintWidget.C is in witty-examples 3.3.0-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | /*
* Copyright (C) 2010 Emweb bvba, Heverlee, Belgium.
*
* See the LICENSE file for terms of use.
*/
#include "PaintWidget.h"
#include <Wt/WGLWidget>
#include <Wt/WMatrix4x4>
#include <Wt/WMemoryResource>
using namespace Wt;
// To avoid copying large constant data around, the data points are stored
// in a global variable.
extern std::vector<float> data;
// Calculates the centerpoint of the data. This is where the camera looks at.
void centerpoint(double &x, double &y, double &z)
{
double minx, miny, minz;
double maxx, maxy, maxz;
minx = maxx = data[0];
miny = maxy = data[1];
minz = maxz = data[2];
for (unsigned int i = 0; i < data.size()/6; ++i) {
if (data[i*6] < minx) minx = data[i*6];
if (data[i*6] > maxx) maxx = data[i*6];
if (data[i*6 + 1] < miny) miny = data[i*6 + 1];
if (data[i*6 + 1] > maxy) maxy = data[i*6 + 1];
if (data[i*6 + 2] < minz) minz = data[i*6 + 2];
if (data[i*6 + 2] > maxz) maxz = data[i*6 + 2];
}
x = (minx + maxx)/2.;
y = (miny + maxy)/2.;
z = (minz + maxz)/2.;
}
PaintWidget::PaintWidget(WContainerWidget *root, const bool & useBinaryBuffers):
WGLWidget(root), useBinaryBuffers_(useBinaryBuffers)
{
}
// The initializeGL() captures all JS commands that are to be executed
// before the scene is rendered for the first time. It is executed only
// once. It is re-executed when the WebGL context is restored after it
// was lost.
// In general, it should be used to set up shaders, create VBOs, initialize
// matrices, ...
void PaintWidget::initializeGL()
{
// In order to know where to look at, calculate the centerpoint of the
// scene
double cx, cy, cz;
centerpoint(cx, cy, cz);
// Transform the world so that we look at the centerpoint of the scene
WMatrix4x4 worldTransform;
worldTransform.lookAt(
cx, cy, cz + 10, // camera position
cx, cy, cz, // looking at
0, 1, 0); // 'up' vector
// We want to be able to change the camera position client-side. In
// order to do so, the world transformation matrix must be stored in
// a matrix that can be manipulated from JavaScript.
jsMatrix_ = createJavaScriptMatrix4();
setJavaScriptMatrix4(jsMatrix_, worldTransform);
// This installs a client-side mouse handler that modifies the
// world transformation matrix. Like WMatrix4x4::lookAt, this works
// by specifying a center point and an up direction; mouse movements
// will allow the camera to be moved around the center point.
setClientSideLookAtHandler(jsMatrix_, // the name of the JS matrix
cx, cy, cz, // the center point
0, 1, 0, // the up direction
0.005, 0.005); // 'speed' factors
// Alternative: this installs a client-side mouse handler that allows
// to 'walk' around: go forward, backward, turn left, turn right, ...
//setClientSideWalkHandler(jsMatrix_, 0.05, 0.005);
// First, load a simple shader
Shader fragmentShader = createShader(FRAGMENT_SHADER);
shaderSource(fragmentShader, fragmentShader_);
compileShader(fragmentShader);
Shader vertexShader = createShader(VERTEX_SHADER);
shaderSource(vertexShader, vertexShader_);
compileShader(vertexShader);
shaderProgram_ = createProgram();
attachShader(shaderProgram_, vertexShader);
attachShader(shaderProgram_, fragmentShader);
linkProgram(shaderProgram_);
useProgram(shaderProgram_);
// Extract the references to the attributes from the shader.
vertexNormalAttribute_ =
getAttribLocation(shaderProgram_, "aVertexNormal");
vertexPositionAttribute_ =
getAttribLocation(shaderProgram_, "aVertexPosition");
enableVertexAttribArray(vertexPositionAttribute_);
enableVertexAttribArray(vertexNormalAttribute_);
// Extract the references the uniforms from the shader
pMatrixUniform_ = getUniformLocation(shaderProgram_, "uPMatrix");
cMatrixUniform_ = getUniformLocation(shaderProgram_, "uCMatrix");
mvMatrixUniform_ = getUniformLocation(shaderProgram_, "uMVMatrix");
nMatrixUniform_ = getUniformLocation(shaderProgram_, "uNMatrix");
// Create a Vertex Buffer Object (VBO) and load all polygon's data
// (points, normals) into it. In this case we use one VBO that contains
// all data (6 per point: vx, vy, vz, nx, ny, nz); alternatively you
// can use multiple VBO's (e.g. one VBO for normals, one for points,
// one for texture coordinates).
// Note that if you use indexed buffers, you cannot have indexes
// larger than 65K, due to the limitations of WebGL.
objBuffer_ = createBuffer();
bindBuffer(ARRAY_BUFFER, objBuffer_);
if (!useBinaryBuffers_)
{
// embed the buffer directly in the JavaScript stream.
bufferDatafv(ARRAY_BUFFER, data.begin(), data.end(), STATIC_DRAW);
}else
{
//Alternatively uncomment the following lines to directly transfer the array
//as a binary data resource.
//The binary data is prepared as a downloadable resource which is requested
//by an XHR of the javascript client
WMemoryResource * mem = new WMemoryResource("application/octet", this);
// cast the doubles to an unsigned char array to serve it by the memory resource
mem->setData(
reinterpret_cast<unsigned char*>(&(data[0])),
data.size() * sizeof(float));
// create client side identifier for the buffer resource and set up for preloading
ArrayBuffer clientBufferResource = createAndLoadArrayBuffer(mem->generateUrl());
bufferData(ARRAY_BUFFER, clientBufferResource, STATIC_DRAW);
}
// Set the clear color to a transparant background
clearColor(0, 0, 0, 0);
// Reset Z-buffer, enable Z-buffering
clearDepth(1);
enable(DEPTH_TEST);
depthFunc(LEQUAL);
}
void PaintWidget::resizeGL(int width, int height)
{
// Set the viewport size.
viewport(0, 0, width, height);
// Set projection matrix to some fixed values
WMatrix4x4 proj;
proj.perspective(45, ((double)width)/height, 1, 40);
uniformMatrix4(pMatrixUniform_, proj);
}
// The paintGL function is executed every time the canvas is to be
// repainted. For example: when the camera location is modified,
// an animated object is changed, ...
void PaintWidget::paintGL()
{
// Clear color an depth buffers
clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT);
// Configure the shader: set the uniforms
// Uniforms are 'configurable constants' in a shader: they are
// identical for every point that has to be drawn.
// Set the camera transformation to the value of a client-side JS matrix
uniformMatrix4(cMatrixUniform_, jsMatrix_);
// Often, a model matrix is used to move the model around. We're happy
// with the location of the model, so we leave it as the unit matrix
WMatrix4x4 modelMatrix;
uniformMatrix4(mvMatrixUniform_, modelMatrix);
// The next one is a bit complicated. In desktop OpenGL, a shader
// has the gl_NormalMatrix matrix available in the shader language,
// a matrix that is used to transform normals to e.g. implement proper
// Phong shading (google will help you to find a detailed explanation
// of why you need it). It is the transposed inverse of the model view
// matrix. Unfortunately, this matrix is not available in WebGL, so if
// you want to do phong shading, you must calculate it yourself.
// Wt provides methods to calculate the transposed inverse of a matrix,
// when client-side JS matrices are involved. Here, we inverse-transpose
// the product of the client-side camera matrix and the model matrix.
uniformMatrix4(nMatrixUniform_, (jsMatrix_ * modelMatrix).inverted().transposed());
// Configure the shaders: set the attributes.
// Attributes are 'variables' within a shader: they vary for every point
// that has to be drawn. All are stored in one VBO.
bindBuffer(ARRAY_BUFFER, objBuffer_);
// Configure the vertex attributes:
vertexAttribPointer(vertexPositionAttribute_,
3, // size: Every vertex has an X, Y anc Z component
FLOAT, // type: They are floats
false, // normalized: Please, do NOT normalize the vertices
2*3*4, // stride: The first byte of the next vertex is located this
// amount of bytes further. The format of the VBO is
// vx, vy, vz, nx, ny, nz and every element is a
// Float32, hence 4 bytes large
0); // offset: The byte position of the first vertex in the buffer
// is 0.
vertexAttribPointer(vertexNormalAttribute_,
3,
FLOAT,
false,
2*3*4, // stride: see above. We jump from normal to normal now
3*4); // offset: the first normal is located after the first vertex
// position, consisting of three four-byte floats
// Now draw all the triangles.
drawArrays(TRIANGLES, 0, data.size()/6);
}
void PaintWidget::setShaders(const std::string &vertexShader,
const std::string &fragmentShader)
{
vertexShader_ = vertexShader;
fragmentShader_ = fragmentShader;
}
|