Merge branch 'annot6' into 'master'

Adding text annotations to rendering

This adds bitmap font support and two types of text annotations - screen space text and world-space billboard text - as well as enables the labels in the axes.

See merge request !423
This commit is contained in:
Jeremy Meredith 2016-06-01 14:35:06 -04:00
commit 298b9d2e6c
23 changed files with 11816 additions and 774 deletions

@ -170,7 +170,7 @@ main(int argc, char* argv[])
vtkm::rendering::RenderSurfaceGL surface(W,H,bg);
vtkm::rendering::SceneRendererGL<VTKM_DEFAULT_DEVICE_ADAPTER_TAG> sceneRenderer;
vtkm::rendering::Scene3D scene;
vtkm::rendering::Scene scene;
scene.Plots.push_back(vtkm::rendering::Plot(ds.GetCellSet(),
ds.GetCoordinateSystem(),
ds.GetField("pointvar"),

@ -28,6 +28,7 @@
#include <vtkm/rendering/RenderSurface.h>
#include <vtkm/rendering/WorldAnnotator.h>
#include <vtkm/rendering/AxisAnnotation.h>
#include <vtkm/rendering/TextAnnotation.h>
namespace vtkm {
namespace rendering {
@ -39,15 +40,15 @@ protected:
vtkm::Float64 min_tx, min_ty, min_toff;
vtkm::Float64 x0, y0, x1, y1;
vtkm::Float64 lower, upper;
vtkm::Float64 fontscale;
vtkm::Float32 fontscale;
vtkm::Float32 linewidth;
vtkm::rendering::Color color;
bool logarithmic;
#if 0
eavlTextAnnotation::HorizontalAlignment halign;
eavlTextAnnotation::VerticalAlignment valign;
std::vector<eavlTextAnnotation*> labels;
#endif
TextAnnotation::HorizontalAlignment halign;
TextAnnotation::VerticalAlignment valign;
std::vector<TextAnnotation*> labels;
std::vector<vtkm::Float64> maj_positions;
std::vector<vtkm::Float64> maj_proportions;
@ -55,23 +56,17 @@ protected:
std::vector<vtkm::Float64> min_positions;
std::vector<vtkm::Float64> min_proportions;
///\todo: Don't need anymore??
bool worldSpace;
int moreOrLessTickAdjustment;
public:
AxisAnnotation2D() : AxisAnnotation()
{
#if 0
halign = eavlTextAnnotation::HCenter;
valign = eavlTextAnnotation::VCenter;
#endif
fontscale = 0.05;
halign = TextAnnotation::HCenter;
valign = TextAnnotation::VCenter;
fontscale = 0.05f;
linewidth = 1.0;
color = Color(1,1,1);
logarithmic = false;
moreOrLessTickAdjustment = 0;
worldSpace = false;
}
virtual ~AxisAnnotation2D()
{
@ -82,10 +77,6 @@ public:
logarithmic = l;
}
#endif
void SetWorldSpace(bool ws)
{
worldSpace = ws;
}
void SetMoreOrLessTickAdjustment(int offset)
{
moreOrLessTickAdjustment = offset;
@ -123,21 +114,17 @@ public:
x1 = x1_;
y1 = y1_;
}
#if 0
void SetLabelAlignment(eavlTextAnnotation::HorizontalAlignment h,
eavlTextAnnotation::VerticalAlignment v)
void SetLabelAlignment(TextAnnotation::HorizontalAlignment h,
TextAnnotation::VerticalAlignment v)
{
halign = h;
valign = v;
}
#endif
void SetLabelFontScale(vtkm::Float64 s)
void SetLabelFontScale(vtkm::Float32 s)
{
fontscale = s;
#if 0
for (unsigned int i=0; i<labels.size(); i++)
labels[i]->SetScale(s);
#endif
}
void SetRangeForAutoTicks(vtkm::Float64 l, vtkm::Float64 u)
{
@ -173,33 +160,22 @@ public:
min_proportions.clear();
min_proportions.insert(min_proportions.begin(), prop.begin(), prop.end());
}
virtual void Render(View &,
WorldAnnotator &,
virtual void Render(View &view,
WorldAnnotator &worldAnnotator,
RenderSurface &renderSurface)
{
renderSurface.AddLine(x0,y0, x1,y1, linewidth, color);
// major ticks
unsigned int nmajor = (unsigned int)maj_proportions.size();
#if 0
while (labels.size() < nmajor)
{
if (worldSpace)
{
labels.push_back(new eavlBillboardTextAnnotation(win,"test",
color,
fontscale,
0,0,0, true));
}
else
{
labels.push_back(new eavlScreenTextAnnotation(win,"test",
color,
fontscale,
0,0, 0));
}
labels.push_back(new ScreenTextAnnotation("test",
color,
fontscale,
0,0, 0));
}
#endif
for (unsigned int i=0; i<nmajor; ++i)
{
vtkm::Float64 xc = x0 + (x1-x0) * maj_proportions[i];
@ -220,17 +196,13 @@ public:
char val[256];
snprintf(val, 256, "%g", maj_positions[i]);
#if 0
labels[i]->SetText(val);
//if (fabs(maj_positions[i]) < 1e-10)
// labels[i]->SetText("0");
if (worldSpace)
((eavlBillboardTextAnnotation*)(labels[i]))->SetPosition(xs,ys,0);
else
((eavlScreenTextAnnotation*)(labels[i]))->SetPosition(xs,ys);
((ScreenTextAnnotation*)(labels[i]))->SetPosition(vtkm::Float32(xs),
vtkm::Float32(ys));
labels[i]->SetAlignment(halign,valign);
#endif
}
// minor ticks
@ -250,13 +222,10 @@ public:
}
}
#if 0
for (int i=0; i<nmajor; ++i)
for (unsigned int i=0; i<nmajor; ++i)
{
labels[i]->Render(view);
labels[i]->Render(view, worldAnnotator, renderSurface);
}
#endif
}
};

@ -27,6 +27,7 @@
#include <vtkm/rendering/Scene.h>
#include <vtkm/rendering/WorldAnnotator.h>
#include <vtkm/rendering/AxisAnnotation.h>
#include <vtkm/rendering/TextAnnotation.h>
namespace vtkm {
namespace rendering {
@ -38,20 +39,22 @@ protected:
vtkm::Float64 maj_size, maj_toff;
vtkm::Float64 min_size, min_toff;
int axis;
vtkm::Float64 invertx, inverty, invertz;
vtkm::Float32 invertx, inverty, invertz;
vtkm::Float64 x0, y0, z0, x1, y1, z1;
vtkm::Float64 lower, upper;
vtkm::Float64 fontscale;
vtkm::Float32 fontoffset;
vtkm::Float32 linewidth;
vtkm::rendering::Color color;
//vector<BillboardTextAnnotation*> labels; ///<\todo: add text back in
std::vector<BillboardTextAnnotation*> labels;
int moreOrLessTickAdjustment;
public:
AxisAnnotation3D() : AxisAnnotation()
{
axis = 0;
color = Color(1,1,1);
fontscale = 0.05;
fontoffset = 0.1f; // world space offset from axis
fontscale = 0.05; // screen space font size
linewidth = 1.0;
color = Color(1,1,1);
moreOrLessTickAdjustment = 0;
@ -104,21 +107,24 @@ public:
void SetLabelFontScale(vtkm::Float64 s)
{
fontscale = s;
#if 0
for (unsigned int i=0; i<labels.size(); i++)
labels[i]->SetScale(s);
#endif
labels[i]->SetScale(vtkm::Float32(s));
}
void SetLabelFontOffset(vtkm::Float32 off)
{
fontoffset = off;
}
void SetRange(vtkm::Float64 l, vtkm::Float64 u)
{
lower = l;
upper = u;
}
virtual void Render(View &,
WorldAnnotator &worldannotator)
virtual void Render(View &view,
WorldAnnotator &worldAnnotator,
RenderSurface &renderSurface)
{
bool infront = true;
worldannotator.AddLine(x0,y0,z0,
worldAnnotator.AddLine(x0,y0,z0,
x1,y1,z1,
linewidth, color, infront);
@ -127,15 +133,15 @@ public:
// major ticks
CalculateTicks(lower, upper, false, positions, proportions, moreOrLessTickAdjustment);
unsigned int nmajor = (unsigned int)proportions.size();
#if 0
while ((int)labels.size() < nmajor)
while (labels.size() < nmajor)
{
labels.push_back(new BillboardTextAnnotation(win,"test",
color,
fontscale,
0,0,0, false, 0));
labels.push_back(new BillboardTextAnnotation("test",
color,
vtkm::Float32(fontscale),
0,0,0,
0));
}
#endif
for (unsigned int i=0; i<nmajor; ++i)
{
vtkm::Float64 xc = x0 + (x1-x0) * proportions[i];
@ -160,33 +166,33 @@ public:
vtkm::Float64 zs = zc - tz*maj_toff;
vtkm::Float64 ze = zc + tz*(1. - maj_toff);
worldannotator.AddLine(xs,ys,zs,
xe,ye,ze,
linewidth, color, infront);
worldAnnotator.AddLine(xs,ys,zs,
xe,ye,ze,
linewidth, color, infront);
}
vtkm::Float64 tx=0, ty=0, tz=0;
const vtkm::Float64 s = 0.4;
vtkm::Float32 tx=0, ty=0, tz=0;
const vtkm::Float32 s = 0.4f;
switch (axis)
{
case 0: ty=s*fontscale; tz=s*fontscale; break;
case 1: tx=s*fontscale; tz=s*fontscale; break;
case 2: tx=s*fontscale; ty=s*fontscale; break;
case 0: ty=s*fontoffset; tz=s*fontoffset; break;
case 1: tx=s*fontoffset; tz=s*fontoffset; break;
case 2: tx=s*fontoffset; ty=s*fontoffset; break;
}
tx *= invertx;
ty *= inverty;
tz *= invertz;
#if 0
char val[256];
snprintf(val, 256, "%g", positions[i]);
labels[i]->SetText(val);
//if (fabs(positions[i]) < 1e-10)
// labels[i]->SetText("0");
labels[i]->SetPosition(xc - tx, yc - ty, zc - tz);
labels[i]->SetPosition(vtkm::Float32(xc - tx),
vtkm::Float32(yc - ty),
vtkm::Float32(zc - tz));
labels[i]->SetAlignment(TextAnnotation::HCenter,
TextAnnotation::VCenter);
#endif
}
// minor ticks
@ -216,18 +222,16 @@ public:
vtkm::Float64 zs = zc - tz*min_toff;
vtkm::Float64 ze = zc + tz*(1. - min_toff);
worldannotator.AddLine(xs,ys,zs,
worldAnnotator.AddLine(xs,ys,zs,
xe,ye,ze,
linewidth, color, infront);
}
}
#if 0
for (unsigned int i=0; i<nmajor; ++i)
{
labels[i]->Render(view);
labels[i]->Render(view, worldAnnotator, renderSurface);
}
#endif
}
};

689
vtkm/rendering/BitmapFont.h Normal file

@ -0,0 +1,689 @@
//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//
//=============================================================================
#ifndef vtk_m_BitmapFont_h
#define vtk_m_BitmapFont_h
#include <string>
namespace vtkm {
namespace rendering {
class BitmapFont
{
public:
struct Character
{
std::string id;
char c;
int offx, offy;
int x, y, w, h;
int adv;
int kern[256];
Character()
{
ResetKerning();
}
Character(const std::string &id_, char c_, int offx_, int offy_,
int x_, int y_, int w_, int h_, int adv_)
: id(id_), c(c_), offx(offx_), offy(offy_),
x(x_), y(y_), w(w_), h(h_), adv(adv_)
{
ResetKerning();
}
Character(const std::string &id_, const int metrics[])
: id(id_), c((char)metrics[0]), offx(metrics[1]), offy(metrics[2]),
x(metrics[3]), y(metrics[4]), w(metrics[5]), h(metrics[6]),
adv(metrics[7])
{
ResetKerning();
}
void ResetKerning()
{
for (int i=0; i<256; i++)
kern[i]=0;
}
};
std::string Name;
std::string ImageFile;
int Height;
int Ascender;
int Descender;
int ImgW, ImgH;
int PadL, PadR, PadT, PadB;
int ShortMap[256];
std::vector<Character> Chars;
std::vector<unsigned char> RawImageFileData;
public:
BitmapFont()
{
for (int i=0; i<256; ++i)
ShortMap[i] = 0;
this->PadL=0;
this->PadR=0;
this->PadT=0;
this->PadB=0;
}
Character GetChar(char c)
{
return this->Chars[ShortMap[(unsigned char)c]];
}
std::vector<unsigned char> &GetRawImageData()
{
return this->RawImageFileData;
}
vtkm::Float32 GetTextWidth(const std::string &text)
{
vtkm::Float32 width = 0;
for (unsigned int i=0; i<text.length(); ++i)
{
Character c = GetChar(text[i]);
char nextchar = (i < text.length()-1) ? text[i+1] : 0;
const bool kerning = true;
if (kerning && nextchar>0)
width += vtkm::Float32(c.kern[int(nextchar)]) / vtkm::Float32(this->Height);
width += vtkm::Float32(c.adv) / vtkm::Float32(this->Height);
}
return width;
}
void GetCharPolygon(char character, vtkm::Float32 &x, vtkm::Float32 &y,
vtkm::Float32 &vl, vtkm::Float32 &vr, vtkm::Float32 &vt, vtkm::Float32 &vb,
vtkm::Float32 &tl, vtkm::Float32 &tr, vtkm::Float32 &tt, vtkm::Float32 &tb,
char nextchar = 0)
{
Character c = GetChar(character);
// By default, the origin for the font is at the
// baseline. That's nice, but we'd rather it
// be at the actual bottom, so create an offset.
vtkm::Float32 yoff = -vtkm::Float32(this->Descender) / vtkm::Float32(this->Height);
tl = vtkm::Float32(c.x + this->PadL) / vtkm::Float32(this->ImgW);
tr = vtkm::Float32(c.x + c.w - this->PadR) / vtkm::Float32(this->ImgW);
tt = 1.f - vtkm::Float32(c.y + this->PadT) / vtkm::Float32(this->ImgH);
tb = 1.f - vtkm::Float32(c.y + c.h - this->PadB) / vtkm::Float32(this->ImgH);
vl = x + vtkm::Float32(c.offx + this->PadL) / vtkm::Float32(this->Height);
vr = x + vtkm::Float32(c.offx + c.w - this->PadR) / vtkm::Float32(this->Height);
vt = yoff + y + vtkm::Float32(c.offy - this->PadT) / vtkm::Float32(this->Height);
vb = yoff + y + vtkm::Float32(c.offy - c.h + this->PadB) / vtkm::Float32(this->Height);
const bool kerning = true;
if (kerning && nextchar>0)
x += vtkm::Float32(c.kern[int(nextchar)]) / vtkm::Float32(this->Height);
x += vtkm::Float32(c.adv) / vtkm::Float32(this->Height);
}
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Below is the PicoPNG source file obtained 2013-01-07 from
// http://lodev.org/lodepng/picopng.cpp. It has the following
// modifications relative to the original:
// 1. decodePNG() was made static.
// 2. std:: qualify size_t
// 3. main() and helper code at the bottom of the file was removed.
// 4. remove unused known_type variable.
// 5. added explicit casts to remove compiler warnings
// 6. renamed a function argument to avoid a shadowing warning
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
#include <vector>
/*
decodePNG: The picoPNG function, decodes a PNG file buffer in memory, into a raw pixel buffer.
out_image: output parameter, this will contain the raw pixels after decoding.
By default the output is 32-bit RGBA color.
The std::vector is automatically resized to the correct size.
image_width: output_parameter, this will contain the width of the image in pixels.
image_height: output_parameter, this will contain the height of the image in pixels.
in_png: pointer to the buffer of the PNG file in memory. To get it from a file on
disk, load it and store it in a memory buffer yourself first.
in_size: size of the input PNG file in bytes.
convert_to_rgba32: optional parameter, true by default.
Set to true to get the output in RGBA 32-bit (8 bit per channel) color format
no matter what color type the original PNG image had. This gives predictable,
useable data from any random input PNG.
Set to false to do no color conversion at all. The result then has the same data
type as the PNG image, which can range from 1 bit to 64 bits per pixel.
Information about the color type or palette colors are not provided. You need
to know this information yourself to be able to use the data so this only
works for trusted PNG files. Use LodePNG instead of picoPNG if you need this information.
return: 0 if success, not 0 if some error occured.
*/
static int decodePNG(std::vector<unsigned char>& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, std::size_t in_size, bool convert_to_rgba32=true)
{
// picoPNG version 20101224
// Copyright (c) 2005-2010 Lode Vandevenne
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
// picoPNG is a PNG decoder in one C++ function of around 500 lines. Use picoPNG for
// programs that need only 1 .cpp file. Since it's a single function, it's very limited,
// it can convert a PNG to raw pixel data either converted to 32-bit RGBA color or
// with no color conversion at all. For anything more complex, another tiny library
// is available: LodePNG (lodepng.c(pp)), which is a single source and header file.
// Apologies for the compact code style, it's to make this tiny.
static const unsigned long LENBASE[29] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258};
static const unsigned long LENEXTRA[29] = {0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
static const unsigned long DISTBASE[30] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577};
static const unsigned long DISTEXTRA[30] = {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
static const unsigned long CLCL[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; //code length code lengths
struct Zlib //nested functions for zlib decompression
{
static unsigned long readBitFromStream(std::size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1; bitp++; return result;}
static unsigned long readBitsFromStream(std::size_t& bitp, const unsigned char* bits, std::size_t nbits)
{
unsigned long result = 0;
for(std::size_t i = 0; i < nbits; i++) result += (readBitFromStream(bitp, bits)) << i;
return result;
}
struct HuffmanTree
{
int makeFromLengths(const std::vector<unsigned long>& bitlen, unsigned long maxbitlen)
{ //make tree given the lengths
unsigned long numcodes = (unsigned long)(bitlen.size()), treepos = 0, nodefilled = 0;
std::vector<unsigned long> tree1d(numcodes), blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0);
for(unsigned long bits = 0; bits < numcodes; bits++) blcount[bitlen[bits]]++; //count number of instances of each code length
for(unsigned long bits = 1; bits <= maxbitlen; bits++) nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1;
for(unsigned long n = 0; n < numcodes; n++) if(bitlen[n] != 0) tree1d[n] = nextcode[bitlen[n]]++; //generate all the codes
tree2d.clear(); tree2d.resize(numcodes * 2, 32767); //32767 here means the tree2d isn't filled there yet
for(unsigned long n = 0; n < numcodes; n++) //the codes
for(unsigned long i = 0; i < bitlen[n]; i++) //the bits for this code
{
unsigned long bit = (tree1d[n] >> (bitlen[n] - i - 1)) & 1;
if(treepos > numcodes - 2) return 55;
if(tree2d[2 * treepos + bit] == 32767) //not yet filled in
{
if(i + 1 == bitlen[n]) { tree2d[2 * treepos + bit] = n; treepos = 0; } //last bit
else { tree2d[2 * treepos + bit] = ++nodefilled + numcodes; treepos = nodefilled; } //addresses are encoded as values > numcodes
}
else treepos = tree2d[2 * treepos + bit] - numcodes; //subtract numcodes from address to get address value
}
return 0;
}
int decode(bool& decoded, unsigned long& result, std::size_t& treepos, unsigned long bit) const
{ //Decodes a symbol from the tree
unsigned long numcodes = (unsigned long)tree2d.size() / 2;
if(treepos >= numcodes) return 11; //error: you appeared outside the codetree
result = tree2d[2 * treepos + bit];
decoded = (result < numcodes);
treepos = decoded ? 0 : result - numcodes;
return 0;
}
std::vector<unsigned long> tree2d; //2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all nodes and leaves of the tree.
};
struct Inflator
{
int error;
void inflate(std::vector<unsigned char>& out, const std::vector<unsigned char>& in, std::size_t inpos = 0)
{
std::size_t bp = 0, pos = 0; //bit pointer and byte pointer
error = 0;
unsigned long BFINAL = 0;
while(!BFINAL && !error)
{
if(bp >> 3 >= in.size()) { error = 52; return; } //error, bit pointer will jump past memory
BFINAL = readBitFromStream(bp, &in[inpos]);
unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); BTYPE += 2 * readBitFromStream(bp, &in[inpos]);
if(BTYPE == 3) { error = 20; return; } //error: invalid BTYPE
else if(BTYPE == 0) inflateNoCompression(out, &in[inpos], bp, pos, in.size());
else inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), BTYPE);
}
if(!error) out.resize(pos); //Only now we know the true size of out, resize it to that
}
void generateFixedTrees(HuffmanTree& tree, HuffmanTree& treeD) //get the tree of a deflated block with fixed tree
{
std::vector<unsigned long> bitlen(288, 8), bitlenD(32, 5);;
for(std::size_t i = 144; i <= 255; i++) bitlen[i] = 9;
for(std::size_t i = 256; i <= 279; i++) bitlen[i] = 7;
tree.makeFromLengths(bitlen, 15);
treeD.makeFromLengths(bitlenD, 15);
}
HuffmanTree codetree, codetreeD, codelengthcodetree; //the code tree for Huffman codes, dist codes, and code length codes
unsigned long huffmanDecodeSymbol(const unsigned char* in, std::size_t& bp, const HuffmanTree& lcodetree, std::size_t inlength)
{ //decode a single symbol from given list of bits with given code tree. return value is the symbol
bool decoded; unsigned long ct;
for(std::size_t treepos = 0;;)
{
if((bp & 0x07) == 0 && (bp >> 3) > inlength) { error = 10; return 0; } //error: end reached without endcode
error = lcodetree.decode(decoded, ct, treepos, readBitFromStream(bp, in)); if(error) return 0; //stop, an error happened
if(decoded) return ct;
}
}
void getTreeInflateDynamic(HuffmanTree& tree, HuffmanTree& treeD, const unsigned char* in, std::size_t& bp, std::size_t inlength)
{ //get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree
std::vector<unsigned long> bitlen(288, 0), bitlenD(32, 0);
if(bp >> 3 >= inlength - 2) { error = 49; return; } //the bit pointer is or will go past the memory
std::size_t HLIT = readBitsFromStream(bp, in, 5) + 257; //number of literal/length codes + 257
std::size_t HDIST = readBitsFromStream(bp, in, 5) + 1; //number of dist codes + 1
std::size_t HCLEN = readBitsFromStream(bp, in, 4) + 4; //number of code length codes + 4
std::vector<unsigned long> codelengthcode(19); //lengths of tree to decode the lengths of the dynamic tree
for(std::size_t i = 0; i < 19; i++) codelengthcode[CLCL[i]] = (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0;
error = codelengthcodetree.makeFromLengths(codelengthcode, 7); if(error) return;
std::size_t i = 0, replength;
while(i < HLIT + HDIST)
{
unsigned long code = huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength); if(error) return;
if(code <= 15) { if(i < HLIT) bitlen[i++] = code; else bitlenD[i++ - HLIT] = code; } //a length code
else if(code == 16) //repeat previous
{
if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
replength = 3 + readBitsFromStream(bp, in, 2);
unsigned long value; //set value to the previous code
if((i - 1) < HLIT) value = bitlen[i - 1];
else value = bitlenD[i - HLIT - 1];
for(std::size_t n = 0; n < replength; n++) //repeat this value in the next lengths
{
if(i >= HLIT + HDIST) { error = 13; return; } //error: i is larger than the amount of codes
if(i < HLIT) bitlen[i++] = value; else bitlenD[i++ - HLIT] = value;
}
}
else if(code == 17) //repeat "0" 3-10 times
{
if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
replength = 3 + readBitsFromStream(bp, in, 3);
for(std::size_t n = 0; n < replength; n++) //repeat this value in the next lengths
{
if(i >= HLIT + HDIST) { error = 14; return; } //error: i is larger than the amount of codes
if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
}
}
else if(code == 18) //repeat "0" 11-138 times
{
if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
replength = 11 + readBitsFromStream(bp, in, 7);
for(std::size_t n = 0; n < replength; n++) //repeat this value in the next lengths
{
if(i >= HLIT + HDIST) { error = 15; return; } //error: i is larger than the amount of codes
if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
}
}
else { error = 16; return; } //error: somehow an unexisting code appeared. This can never happen.
}
if(bitlen[256] == 0) { error = 64; return; } //the length of the end code 256 must be larger than 0
error = tree.makeFromLengths(bitlen, 15); if(error) return; //now we've finally got HLIT and HDIST, so generate the code trees, and the function is done
error = treeD.makeFromLengths(bitlenD, 15); if(error) return;
}
void inflateHuffmanBlock(std::vector<unsigned char>& out, const unsigned char* in, std::size_t& bp, std::size_t& pos, std::size_t inlength, unsigned long btype)
{
if(btype == 1) { generateFixedTrees(codetree, codetreeD); }
else if(btype == 2) { getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength); if(error) return; }
for(;;)
{
unsigned long code = huffmanDecodeSymbol(in, bp, codetree, inlength); if(error) return;
if(code == 256) return; //end code
else if(code <= 255) //literal symbol
{
if(pos >= out.size()) out.resize((pos + 1) * 2); //reserve more room
out[pos++] = (unsigned char)(code);
}
else if(code >= 257 && code <= 285) //length code
{
std::size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257];
if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
length += readBitsFromStream(bp, in, numextrabits);
unsigned long codeD = huffmanDecodeSymbol(in, bp, codetreeD, inlength); if(error) return;
if(codeD > 29) { error = 18; return; } //error: invalid dist code (30-31 are never used)
unsigned long dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD];
if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
dist += readBitsFromStream(bp, in, numextrabitsD);
std::size_t start = pos, back = start - dist; //backwards
if(pos + length >= out.size()) out.resize((pos + length) * 2); //reserve more room
for(std::size_t i = 0; i < length; i++) { out[pos++] = out[back++]; if(back >= start) back = start - dist; }
}
}
}
void inflateNoCompression(std::vector<unsigned char>& out, const unsigned char* in, std::size_t& bp, std::size_t& pos, std::size_t inlength)
{
while((bp & 0x7) != 0) bp++; //go to first boundary of byte
std::size_t p = bp / 8;
if(p >= inlength - 4) { error = 52; return; } //error, bit pointer will jump past memory
unsigned long LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3]; p += 4;
if(LEN + NLEN != 65535) { error = 21; return; } //error: NLEN is not one's complement of LEN
if(pos + LEN >= out.size()) out.resize(pos + LEN);
if(p + LEN > inlength) { error = 23; return; } //error: reading outside of in buffer
for(unsigned long n = 0; n < LEN; n++) out[pos++] = in[p++]; //read LEN bytes of literal data
bp = p * 8;
}
};
int decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in) //returns error value
{
Inflator inflator;
if(in.size() < 2) { return 53; } //error, size of zlib data too small
if((in[0] * 256 + in[1]) % 31 != 0) { return 24; } //error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way
unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1;
if(CM != 8 || CINFO > 7) { return 25; } //error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec
if(FDICT != 0) { return 26; } //error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary."
inflator.inflate(out, in, 2);
return inflator.error; //note: adler32 checksum was skipped and ignored
}
};
struct PNG //nested functions for PNG decoding
{
struct Info
{
unsigned long width, height, colorType, bitDepth, compressionMethod, filterMethod, interlaceMethod, key_r, key_g, key_b;
bool key_defined; //is a transparent color key given?
std::vector<unsigned char> palette;
} info;
int error;
void decode(std::vector<unsigned char>& out, const unsigned char* in, std::size_t size, bool convert_to_rgba32)
{
error = 0;
if(size == 0 || in == 0) { error = 48; return; } //the given data is empty
readPngHeader(&in[0], size); if(error) return;
std::size_t pos = 33; //first byte of the first chunk after the header
std::vector<unsigned char> idat; //the data from idat chunks
bool IEND = false;
info.key_defined = false;
while(!IEND) //loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer
{
if(pos + 8 >= size) { error = 30; return; } //error: size of the in buffer too small to contain next chunk
std::size_t chunkLength = read32bitInt(&in[pos]); pos += 4;
if(chunkLength > 2147483647) { error = 63; return; }
if(pos + chunkLength >= size) { error = 35; return; } //error: size of the in buffer too small to contain next chunk
if(in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T') //IDAT chunk, containing compressed image data
{
idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]);
pos += (4 + chunkLength);
}
else if(in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D') { pos += 4; IEND = true; }
else if(in[pos + 0] == 'P' && in[pos + 1] == 'L' && in[pos + 2] == 'T' && in[pos + 3] == 'E') //palette chunk (PLTE)
{
pos += 4; //go after the 4 letters
info.palette.resize(4 * (chunkLength / 3));
if(info.palette.size() > (4 * 256)) { error = 38; return; } //error: palette too big
for(std::size_t i = 0; i < info.palette.size(); i += 4)
{
for(std::size_t j = 0; j < 3; j++) info.palette[i + j] = in[pos++]; //RGB
info.palette[i + 3] = 255; //alpha
}
}
else if(in[pos + 0] == 't' && in[pos + 1] == 'R' && in[pos + 2] == 'N' && in[pos + 3] == 'S') //palette transparency chunk (tRNS)
{
pos += 4; //go after the 4 letters
if(info.colorType == 3)
{
if(4 * chunkLength > info.palette.size()) { error = 39; return; } //error: more alpha values given than there are palette entries
for(std::size_t i = 0; i < chunkLength; i++) info.palette[4 * i + 3] = in[pos++];
}
else if(info.colorType == 0)
{
if(chunkLength != 2) { error = 40; return; } //error: this chunk must be 2 bytes for greyscale image
info.key_defined = 1; info.key_r = info.key_g = info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2;
}
else if(info.colorType == 2)
{
if(chunkLength != 6) { error = 41; return; } //error: this chunk must be 6 bytes for RGB image
info.key_defined = 1;
info.key_r = 256 * in[pos] + in[pos + 1]; pos += 2;
info.key_g = 256 * in[pos] + in[pos + 1]; pos += 2;
info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2;
}
else { error = 42; return; } //error: tRNS chunk not allowed for other color models
}
else //it's not an implemented chunk type, so ignore it: skip over the data
{
if(!(in[pos + 0] & 32)) { error = 69; return; } //error: unknown critical chunk (5th bit of first byte of chunk type is 0)
pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk
}
pos += 4; //step over CRC (which is ignored)
}
unsigned long bpp = getBpp(info);
std::vector<unsigned char> scanlines(((info.width * (info.height * bpp + 7)) / 8) + info.height); //now the out buffer will be filled
Zlib zlib; //decompress with the Zlib decompressor
error = zlib.decompress(scanlines, idat); if(error) return; //stop if the zlib decompressor returned an error
std::size_t bytewidth = (bpp + 7) / 8, outlength = (info.height * info.width * bpp + 7) / 8;
out.resize(outlength); //time to fill the out buffer
unsigned char* out_ = outlength ? &out[0] : 0; //use a regular pointer to the std::vector for faster code if compiled without optimization
if(info.interlaceMethod == 0) //no interlace, just filter
{
std::size_t linestart = 0, linelength = (info.width * bpp + 7) / 8; //length in bytes of a scanline, excluding the filtertype byte
if(bpp >= 8) //byte per byte
for(unsigned long y = 0; y < info.height; y++)
{
unsigned long filterType = scanlines[linestart];
const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth];
unFilterScanline(&out_[linestart - y], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return;
linestart += (1 + linelength); //go to start of next scanline
}
else //less than 8 bits per pixel, so fill it up bit per bit
{
std::vector<unsigned char> templine((info.width * bpp + 7) >> 3); //only used if bpp < 8
for(std::size_t y = 0, obp = 0; y < info.height; y++)
{
unsigned long filterType = scanlines[linestart];
const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth];
unFilterScanline(&templine[0], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return;
for(std::size_t bp = 0; bp < info.width * bpp;) setBitOfReversedStream(obp, out_, readBitFromReversedStream(bp, &templine[0]));
linestart += (1 + linelength); //go to start of next scanline
}
}
}
else //interlaceMethod is 1 (Adam7)
{
std::size_t passw[7] = { (info.width + 7) / 8, (info.width + 3) / 8, (info.width + 3) / 4, (info.width + 1) / 4, (info.width + 1) / 2, (info.width + 0) / 2, (info.width + 0) / 1 };
std::size_t passh[7] = { (info.height + 7) / 8, (info.height + 7) / 8, (info.height + 3) / 8, (info.height + 3) / 4, (info.height + 1) / 4, (info.height + 1) / 2, (info.height + 0) / 2 };
std::size_t passstart[7] = {0};
std::size_t pattern[28] = {0,4,0,2,0,1,0,0,0,4,0,2,0,1,8,8,4,4,2,2,1,8,8,8,4,4,2,2}; //values for the adam7 passes
for(int i = 0; i < 6; i++) passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * bpp + 7) / 8);
std::vector<unsigned char> scanlineo((info.width * bpp + 7) / 8), scanlinen((info.width * bpp + 7) / 8); //"old" and "new" scanline
for(int i = 0; i < 7; i++)
adam7Pass(&out_[0], &scanlinen[0], &scanlineo[0], &scanlines[passstart[i]], info.width, pattern[i], pattern[i + 7], pattern[i + 14], pattern[i + 21], passw[i], passh[i], bpp);
}
if(convert_to_rgba32 && (info.colorType != 6 || info.bitDepth != 8)) //conversion needed
{
std::vector<unsigned char> data = out;
error = convert(out, &data[0], info, info.width, info.height);
}
}
void readPngHeader(const unsigned char* in, std::size_t inlength) //read the information from the header and store it in the Info
{
if(inlength < 29) { error = 27; return; } //error: the data length is smaller than the length of the header
if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { error = 28; return; } //no PNG signature
if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { error = 29; return; } //error: it doesn't start with a IHDR chunk!
info.width = read32bitInt(&in[16]); info.height = read32bitInt(&in[20]);
info.bitDepth = in[24]; info.colorType = in[25];
info.compressionMethod = in[26]; if(in[26] != 0) { error = 32; return; } //error: only compression method 0 is allowed in the specification
info.filterMethod = in[27]; if(in[27] != 0) { error = 33; return; } //error: only filter method 0 is allowed in the specification
info.interlaceMethod = in[28]; if(in[28] > 1) { error = 34; return; } //error: only interlace methods 0 and 1 exist in the specification
error = checkColorValidity(info.colorType, info.bitDepth);
}
void unFilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, std::size_t bytewidth, unsigned long filterType, std::size_t length)
{
switch(filterType)
{
case 0: for(std::size_t i = 0; i < length; i++) recon[i] = scanline[i]; break;
case 1:
for(std::size_t i = 0; i < bytewidth; i++) recon[i] = (unsigned char)(scanline[i]);
for(std::size_t i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + recon[i - bytewidth]);
break;
case 2:
if(precon) for(std::size_t i = 0; i < length; i++) recon[i] = (unsigned char)(scanline[i] + precon[i]);
else for(std::size_t i = 0; i < length; i++) recon[i] = (unsigned char)(scanline[i]);
break;
case 3:
if(precon)
{
for(std::size_t i = 0; i < bytewidth; i++) recon[i] = (unsigned char)(scanline[i] + precon[i] / 2);
for(std::size_t i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2));
}
else
{
for(std::size_t i = 0; i < bytewidth; i++) recon[i] = (unsigned char)(scanline[i]);
for(std::size_t i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + recon[i - bytewidth] / 2);
}
break;
case 4:
if(precon)
{
for(std::size_t i = 0; i < bytewidth; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(0, precon[i], 0));
for(std::size_t i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
}
else
{
for(std::size_t i = 0; i < bytewidth; i++) recon[i] = (unsigned char)(scanline[i]);
for(std::size_t i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0));
}
break;
default: error = 36; return; //error: unexisting filter type given
}
}
void adam7Pass(unsigned char* out, unsigned char* linen, unsigned char* lineo, const unsigned char* in, unsigned long w, std::size_t passleft, std::size_t passtop, std::size_t spacex, std::size_t spacey, std::size_t passw, std::size_t passh, unsigned long bpp)
{ //filter and reposition the pixels into the output when the image is Adam7 interlaced. This function can only do it after the full image is already decoded. The out buffer must have the correct allocated memory size already.
if(passw == 0) return;
std::size_t bytewidth = (bpp + 7) / 8, linelength = 1 + ((bpp * passw + 7) / 8);
for(unsigned long y = 0; y < passh; y++)
{
unsigned char filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo;
unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType, (w * bpp + 7) / 8); if(error) return;
if(bpp >= 8) for(std::size_t i = 0; i < passw; i++) for(std::size_t b = 0; b < bytewidth; b++) //b = current byte of this pixel
out[bytewidth * w * (passtop + spacey * y) + bytewidth * (passleft + spacex * i) + b] = linen[bytewidth * i + b];
else for(std::size_t i = 0; i < passw; i++)
{
std::size_t obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i), bp = i * bpp;
for(std::size_t b = 0; b < bpp; b++) setBitOfReversedStream(obp, out, readBitFromReversedStream(bp, &linen[0]));
}
unsigned char* temp = linen; linen = lineo; lineo = temp; //swap the two buffer pointers "line old" and "line new"
}
}
static unsigned long readBitFromReversedStream(std::size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1; bitp++; return result;}
static unsigned long readBitsFromReversedStream(std::size_t& bitp, const unsigned char* bits, unsigned long nbits)
{
unsigned long result = 0;
for(std::size_t i = nbits - 1; i < nbits; i--) result += ((readBitFromReversedStream(bitp, bits)) << i);
return result;
}
void setBitOfReversedStream(std::size_t& bitp, unsigned char* bits, unsigned long bit) { bits[bitp >> 3] |= (unsigned char)( (bit << (7 - (bitp & 0x7))) ); bitp++; }
unsigned long read32bitInt(const unsigned char* buffer) { return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; }
int checkColorValidity(unsigned long colorType, unsigned long bd) //return type is a LodePNG error code
{
if((colorType == 2 || colorType == 4 || colorType == 6)) { if(!(bd == 8 || bd == 16)) return 37; else return 0; }
else if(colorType == 0) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; else return 0; }
else if(colorType == 3) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; else return 0; }
else return 31; //unexisting color type
}
unsigned long getBpp(const Info& linfo)
{
if(linfo.colorType == 2) return (3 * linfo.bitDepth);
else if(linfo.colorType >= 4) return (linfo.colorType - 2) * linfo.bitDepth;
else return linfo.bitDepth;
}
int convert(std::vector<unsigned char>& out, const unsigned char* in, Info& infoIn, unsigned long w, unsigned long h)
{ //converts from any color type to 32-bit. return value = LodePNG error code
std::size_t numpixels = w * h, bp = 0;
out.resize(numpixels * 4);
unsigned char* out_ = out.empty() ? 0 : &out[0]; //faster if compiled without optimization
if(infoIn.bitDepth == 8 && infoIn.colorType == 0) //greyscale
for(std::size_t i = 0; i < numpixels; i++)
{
out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[i];
out_[4 * i + 3] = (infoIn.key_defined && in[i] == infoIn.key_r) ? 0 : 255;
}
else if(infoIn.bitDepth == 8 && infoIn.colorType == 2) //RGB color
for(std::size_t i = 0; i < numpixels; i++)
{
for(std::size_t c = 0; c < 3; c++) out_[4 * i + c] = in[3 * i + c];
out_[4 * i + 3] = (infoIn.key_defined == 1 && in[3 * i + 0] == infoIn.key_r && in[3 * i + 1] == infoIn.key_g && in[3 * i + 2] == infoIn.key_b) ? 0 : 255;
}
else if(infoIn.bitDepth == 8 && infoIn.colorType == 3) //indexed color (palette)
for(std::size_t i = 0; i < numpixels; i++)
{
if(4U * in[i] >= infoIn.palette.size()) return 46;
for(std::size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * in[i] + c]; //get rgb colors from the palette
}
else if(infoIn.bitDepth == 8 && infoIn.colorType == 4) //greyscale with alpha
for(std::size_t i = 0; i < numpixels; i++)
{
out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i + 0];
out_[4 * i + 3] = in[2 * i + 1];
}
else if(infoIn.bitDepth == 8 && infoIn.colorType == 6) for(std::size_t i = 0; i < numpixels; i++) for(std::size_t c = 0; c < 4; c++) out_[4 * i + c] = in[4 * i + c]; //RGB with alpha
else if(infoIn.bitDepth == 16 && infoIn.colorType == 0) //greyscale
for(std::size_t i = 0; i < numpixels; i++)
{
out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i];
out_[4 * i + 3] = (infoIn.key_defined && 256U * in[i] + in[i + 1] == infoIn.key_r) ? 0 : 255;
}
else if(infoIn.bitDepth == 16 && infoIn.colorType == 2) //RGB color
for(std::size_t i = 0; i < numpixels; i++)
{
for(std::size_t c = 0; c < 3; c++) out_[4 * i + c] = in[6 * i + 2 * c];
out_[4 * i + 3] = (infoIn.key_defined && 256U*in[6*i+0]+in[6*i+1] == infoIn.key_r && 256U*in[6*i+2]+in[6*i+3] == infoIn.key_g && 256U*in[6*i+4]+in[6*i+5] == infoIn.key_b) ? 0 : 255;
}
else if(infoIn.bitDepth == 16 && infoIn.colorType == 4) //greyscale with alpha
for(std::size_t i = 0; i < numpixels; i++)
{
out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[4 * i]; //most significant byte
out_[4 * i + 3] = in[4 * i + 2];
}
else if(infoIn.bitDepth == 16 && infoIn.colorType == 6) for(std::size_t i = 0; i < numpixels; i++) for(std::size_t c = 0; c < 4; c++) out_[4 * i + c] = in[8 * i + 2 * c]; //RGB with alpha
else if(infoIn.bitDepth < 8 && infoIn.colorType == 0) //greyscale
for(std::size_t i = 0; i < numpixels; i++)
{
unsigned long value = (readBitsFromReversedStream(bp, in, infoIn.bitDepth) * 255) / ((1 << infoIn.bitDepth) - 1); //scale value from 0 to 255
out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = (unsigned char)(value);
out_[4 * i + 3] = (infoIn.key_defined && value && ((1U << infoIn.bitDepth) - 1U) == infoIn.key_r && ((1U << infoIn.bitDepth) - 1U)) ? 0 : 255;
}
else if(infoIn.bitDepth < 8 && infoIn.colorType == 3) //palette
for(std::size_t i = 0; i < numpixels; i++)
{
unsigned long value = readBitsFromReversedStream(bp, in, infoIn.bitDepth);
if(4 * value >= infoIn.palette.size()) return 47;
for(std::size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * value + c]; //get rgb colors from the palette
}
return 0;
}
unsigned char paethPredictor(short a, short b, short c) //Paeth predicter, used by PNG filter type 4
{
short p = short(a + b - c), pa = short(p > a ? (p - a) : (a - p)), pb = short(p > b ? (p - b) : (b - p)), pc = short(p > c ? (p - c) : (c - p));
return (unsigned char)((pa <= pb && pa <= pc) ? a : pb <= pc ? b : c);
}
};
PNG decoder; decoder.decode(out_image, in_png, in_size, convert_to_rgba32);
image_width = decoder.info.width; image_height = decoder.info.height;
return decoder.error;
}
}} //namespace vtkm::rendering
#endif

File diff suppressed because it is too large Load Diff

@ -77,6 +77,8 @@ public:
axis.SetScreenPosition(l,b, r,b);
axis.SetMajorTickSize(0, .02, 1.0);
axis.SetMinorTickSize(0,0,0); // no minor ticks
axis.SetLabelAlignment(TextAnnotation::HCenter,
TextAnnotation::Top);
axis.Render(view, worldAnnotator, renderSurface);
}
};

@ -0,0 +1,281 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2016 Sandia Corporation.
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_MatrixHelpers_h
#define vtk_m_rendering_MatrixHelpers_h
#include <vtkm/Matrix.h>
namespace vtkm {
namespace rendering {
struct MatrixHelpers
{
static VTKM_CONT_EXPORT
void CreateOGLMatrix(const vtkm::Matrix<vtkm::Float32,4,4> &mtx,
vtkm::Float32 *oglM)
{
oglM[ 0] = mtx[0][0];
oglM[ 1] = mtx[1][0];
oglM[ 2] = mtx[2][0];
oglM[ 3] = mtx[3][0];
oglM[ 4] = mtx[0][1];
oglM[ 5] = mtx[1][1];
oglM[ 6] = mtx[2][1];
oglM[ 7] = mtx[3][1];
oglM[ 8] = mtx[0][2];
oglM[ 9] = mtx[1][2];
oglM[10] = mtx[2][2];
oglM[11] = mtx[3][2];
oglM[12] = mtx[0][3];
oglM[13] = mtx[1][3];
oglM[14] = mtx[2][3];
oglM[15] = mtx[3][3];
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> ViewMatrix(const vtkm::Vec<vtkm::Float32,3> &position,
const vtkm::Vec<vtkm::Float32,3> &lookAt,
const vtkm::Vec<vtkm::Float32,3> &up)
{
vtkm::Vec<vtkm::Float32,3> viewDir = position-lookAt;
vtkm::Vec<vtkm::Float32,3> right = vtkm::Cross(up,viewDir);
vtkm::Vec<vtkm::Float32,3> ru = vtkm::Cross(viewDir,right);
vtkm::Normalize(viewDir);
vtkm::Normalize(right);
vtkm::Normalize(ru);
vtkm::Matrix<vtkm::Float32,4,4> matrix;
vtkm::MatrixIdentity(matrix);
matrix(0,0) = right[0];
matrix(0,1) = right[1];
matrix(0,2) = right[2];
matrix(1,0) = ru[0];
matrix(1,1) = ru[1];
matrix(1,2) = ru[2];
matrix(2,0) = viewDir[0];
matrix(2,1) = viewDir[1];
matrix(2,2) = viewDir[2];
matrix(0,3) = -vtkm::dot(right,position);
matrix(1,3) = -vtkm::dot(ru,position);
matrix(2,3) = -vtkm::dot(viewDir,position);
return matrix;
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> WorldMatrix(const vtkm::Vec<vtkm::Float32,3> &neworigin,
const vtkm::Vec<vtkm::Float32,3> &newx,
const vtkm::Vec<vtkm::Float32,3> &newy,
const vtkm::Vec<vtkm::Float32,3> &newz)
{
vtkm::Matrix<vtkm::Float32,4,4> matrix;
vtkm::MatrixIdentity(matrix);
matrix(0,0) = newx[0];
matrix(0,1) = newy[0];
matrix(0,2) = newz[0];
matrix(1,0) = newx[1];
matrix(1,1) = newy[1];
matrix(1,2) = newz[1];
matrix(2,0) = newx[2];
matrix(2,1) = newy[2];
matrix(2,2) = newz[2];
matrix(0,3) = neworigin[0];
matrix(1,3) = neworigin[1];
matrix(2,3) = neworigin[2];
return matrix;
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> ScaleMatrix(const vtkm::Vec<vtkm::Float32,3> &v)
{
return ScaleMatrix(v[0], v[1], v[2]);
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> ScaleMatrix(const vtkm::Float32 &s)
{
return ScaleMatrix(s,s,s);
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> ScaleMatrix(const vtkm::Float32 &x,
const vtkm::Float32 &y,
const vtkm::Float32 &z)
{
vtkm::Matrix<vtkm::Float32,4,4> scaleMatrix(0.0f);
scaleMatrix(0,0) = x;
scaleMatrix(1,1) = y;
scaleMatrix(2,2) = z;
scaleMatrix(3,3) = 1.0f;
return scaleMatrix;
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> TranslateMatrix(const vtkm::Vec<vtkm::Float32,3> &v)
{
return TranslateMatrix(v[0], v[1], v[2]);
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> TranslateMatrix(const vtkm::Float32 &x,
const vtkm::Float32 &y,
const vtkm::Float32 &z)
{
vtkm::Matrix<vtkm::Float32,4,4> translateMatrix;
vtkm::MatrixIdentity(translateMatrix);
translateMatrix(0,3) = x;
translateMatrix(1,3) = y;
translateMatrix(2,3) = z;
return translateMatrix;
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> RotateXMatrix(vtkm::Float32 angleRadians)
{
vtkm::Matrix<vtkm::Float32,4,4> M;
M(0,0) = 1.f;
M(0,1) = 0.f;
M(0,2) = 0.f;
M(0,3) = 0.f;
M(1,0) = 0.f;
M(1,1) = cosf(angleRadians);
M(1,2) = - sinf(angleRadians);
M(1,3) = 0.f;
M(2,0) = 0.f;
M(2,1) = sinf(angleRadians);
M(2,2) = cosf(angleRadians);
M(2,3) = 0.f;
M(3,0) = 0.f;
M(3,1) = 0.f;
M(3,2) = 0.f;
M(3,3) = 1.f;
return M;
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> RotateYMatrix(vtkm::Float32 angleRadians)
{
vtkm::Matrix<vtkm::Float32,4,4> M;
M(0,0) = cosf(angleRadians);
M(0,1) = 0.f;
M(0,2) = sinf(angleRadians);
M(0,3) = 0.f;
M(1,0) = 0.f;
M(1,1) = 1.f;
M(1,2) = 0.f;
M(1,3) = 0.f;
M(2,0) = - sinf(angleRadians);
M(2,1) = 0.f;
M(2,2) = cosf(angleRadians);
M(2,3) = 0.f;
M(3,0) = 0.f;
M(3,1) = 0.f;
M(3,2) = 0.f;
M(3,3) = 1.f;
return M;
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> RotateZMatrix(vtkm::Float32 angleRadians)
{
vtkm::Matrix<vtkm::Float32,4,4> M;
M(0,0) = cosf(angleRadians);
M(0,1) = - sinf(angleRadians);
M(0,2) = 0.f;
M(0,3) = 0.f;
M(1,0) = sinf(angleRadians);
M(1,1) = cosf(angleRadians);
M(1,2) = 0.f;
M(1,3) = 0.f;
M(2,0) = 0.f;
M(2,1) = 0.f;
M(2,2) = 1.f;
M(2,3) = 0.f;
M(3,0) = 0.f;
M(3,1) = 0.f;
M(3,2) = 0.f;
M(3,3) = 1.f;
return M;
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> TrackballMatrix(vtkm::Float32 p1x,
vtkm::Float32 p1y,
vtkm::Float32 p2x,
vtkm::Float32 p2y)
{
const vtkm::Float32 RADIUS = 0.80f; //z value lookAt x = y = 0.0
const vtkm::Float32 COMPRESSION = 3.5f; // multipliers for x and y.
const vtkm::Float32 AR3 = RADIUS*RADIUS*RADIUS;
vtkm::Matrix<vtkm::Float32,4,4> matrix;
vtkm::MatrixIdentity(matrix);
if (p1x==p2x && p1y==p2y) { return matrix; }
vtkm::Vec<vtkm::Float32, 3> p1(p1x,p1y, AR3/((p1x*p1x+p1y*p1y)*COMPRESSION+AR3));
vtkm::Vec<vtkm::Float32, 3> p2(p2x,p2y, AR3/((p2x*p2x+p2y*p2y)*COMPRESSION+AR3));
vtkm::Vec<vtkm::Float32, 3> axis = vtkm::Normal(vtkm::Cross(p2,p1));
vtkm::Vec<vtkm::Float32, 3> p2_p1(p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]);
vtkm::Float32 t = vtkm::Magnitude(p2_p1);
t = vtkm::Min(vtkm::Max(t, -1.0f), 1.0f);
vtkm::Float32 phi = static_cast<vtkm::Float32>(-2.0f*asin(t/(2.0f*RADIUS)));
vtkm::Float32 val = static_cast<vtkm::Float32>(sin(phi/2.0f));
axis[0] *= val;
axis[1] *= val;
axis[2] *= val;
//quaternion
vtkm::Float32 q[4] = {axis[0], axis[1], axis[2], static_cast<vtkm::Float32>(cos(phi/2.0f))};
// normalize quaternion to unit magnitude
t = 1.0f / static_cast<vtkm::Float32>(sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]));
q[0] *= t;
q[1] *= t;
q[2] *= t;
q[3] *= t;
matrix(0,0) = 1 - 2 * (q[1]*q[1] + q[2]*q[2]);
matrix(0,1) = 2 * (q[0]*q[1] + q[2]*q[3]);
matrix(0,2) = (2 * (q[2]*q[0] - q[1]*q[3]) );
matrix(1,0) = 2 * (q[0]*q[1] - q[2]*q[3]);
matrix(1,1) = 1 - 2 * (q[2]*q[2] + q[0]*q[0]);
matrix(1,2) = (2 * (q[1]*q[2] + q[0]*q[3]) );
matrix(2,0) = (2 * (q[2]*q[0] + q[1]*q[3]) );
matrix(2,1) = (2 * (q[1]*q[2] - q[0]*q[3]) );
matrix(2,2) = (1 - 2 * (q[1]*q[1] + q[0]*q[0]) );
return matrix;
}
};
}} //namespace vtkm::rendering
#endif // vtk_m_rendering_MatrixHelpers_h

@ -34,47 +34,54 @@ namespace rendering {
class RenderSurface
{
public:
VTKM_CONT_EXPORT
RenderSurface(std::size_t width=1024, std::size_t height=1024,
const vtkm::rendering::Color &color=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: Width(width), Height(height), BackgroundColor(color)
{
this->ColorBuffer.resize(width*height*4);
this->DepthBuffer.resize(width*height);
}
VTKM_CONT_EXPORT
RenderSurface(std::size_t width=1024, std::size_t height=1024,
const vtkm::rendering::Color &color=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: Width(width), Height(height), BackgroundColor(color)
{
this->ColorBuffer.resize(width*height*4);
this->DepthBuffer.resize(width*height);
}
VTKM_CONT_EXPORT
virtual void Initialize() {}
VTKM_CONT_EXPORT
virtual void Activate() {}
VTKM_CONT_EXPORT
virtual void Clear() {}
VTKM_CONT_EXPORT
virtual void Finish() {}
VTKM_CONT_EXPORT
virtual void Initialize() {}
VTKM_CONT_EXPORT
virtual void Activate() {}
VTKM_CONT_EXPORT
virtual void Clear() {}
VTKM_CONT_EXPORT
virtual void Finish() {}
VTKM_CONT_EXPORT
virtual void SetViewToWorldSpace(vtkm::rendering::View &, bool) {}
VTKM_CONT_EXPORT
virtual void SetViewToScreenSpace(vtkm::rendering::View &, bool) {}
VTKM_CONT_EXPORT
void SetViewportClipping(vtkm::rendering::View &, bool) {}
VTKM_CONT_EXPORT
virtual void SetViewToWorldSpace(vtkm::rendering::View &, bool) {}
VTKM_CONT_EXPORT
virtual void SetViewToScreenSpace(vtkm::rendering::View &, bool) {}
VTKM_CONT_EXPORT
void SetViewportClipping(vtkm::rendering::View &, bool) {}
VTKM_CONT_EXPORT
virtual void SaveAs(const std::string &) {}
VTKM_CONT_EXPORT
virtual void SaveAs(const std::string &) {}
virtual void AddLine(vtkm::Float64, vtkm::Float64,
vtkm::Float64, vtkm::Float64,
vtkm::Float32,
const vtkm::rendering::Color &) {}
virtual void AddColorBar(vtkm::Float32, vtkm::Float32,
vtkm::Float32, vtkm::Float32,
const vtkm::rendering::ColorTable &,
bool) {}
virtual void AddLine(vtkm::Float64, vtkm::Float64,
vtkm::Float64, vtkm::Float64,
vtkm::Float32,
const vtkm::rendering::Color &) {}
virtual void AddColorBar(vtkm::Float32, vtkm::Float32,
vtkm::Float32, vtkm::Float32,
const vtkm::rendering::ColorTable &,
bool) {}
virtual void AddText(vtkm::Float32, vtkm::Float32,
vtkm::Float32,
vtkm::Float32,
vtkm::Float32,
vtkm::Float32, vtkm::Float32,
Color,
std::string) {}
std::size_t Width, Height;
vtkm::rendering::Color BackgroundColor;
std::vector<vtkm::Float32> ColorBuffer;
std::vector<vtkm::Float32> DepthBuffer;
std::size_t Width, Height;
vtkm::rendering::Color BackgroundColor;
std::vector<vtkm::Float32> ColorBuffer;
std::vector<vtkm::Float32> DepthBuffer;
};
}} //namespace vtkm::rendering

@ -24,6 +24,10 @@
#include <vtkm/rendering/View.h>
#include <vtkm/rendering/Color.h>
#include <vtkm/rendering/RenderSurface.h>
#include <vtkm/rendering/BitmapFont.h>
#include <vtkm/rendering/BitmapFontFactory.h>
#include <vtkm/rendering/TextureGL.h>
#include <vtkm/rendering/MatrixHelpers.h>
#include <vtkm/rendering/internal/OpenGLHeaders.h>
#include <iostream>
@ -35,193 +39,266 @@ namespace rendering {
class RenderSurfaceGL : public RenderSurface
{
public:
VTKM_CONT_EXPORT
RenderSurfaceGL(std::size_t w=1024, std::size_t h=1024,
const vtkm::rendering::Color &c=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: RenderSurface(w,h,c)
VTKM_CONT_EXPORT
RenderSurfaceGL(std::size_t w=1024, std::size_t h=1024,
const vtkm::rendering::Color &c=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: RenderSurface(w,h,c)
{
}
VTKM_CONT_EXPORT
virtual void Clear()
{
glClearColor(this->BackgroundColor.Components[0],
this->BackgroundColor.Components[1],
this->BackgroundColor.Components[2],
1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
VTKM_CONT_EXPORT
virtual void Finish()
{
glFinish();
}
VTKM_CONT_EXPORT
virtual void SetViewToWorldSpace(vtkm::rendering::View &v, bool clip)
{
vtkm::Float32 oglP[16], oglM[16];
MatrixHelpers::CreateOGLMatrix(v.CreateProjectionMatrix(), oglP);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(oglP);
MatrixHelpers::CreateOGLMatrix(v.CreateViewMatrix(), oglM);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(oglM);
SetViewportClipping(v, clip);
}
VTKM_CONT_EXPORT
virtual void SetViewToScreenSpace(vtkm::rendering::View &v, bool clip)
{
vtkm::Float32 oglP[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
vtkm::Float32 oglM[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
oglP[0*4+0] = 1.;
oglP[1*4+1] = 1.;
oglP[2*4+2] = -1.;
oglP[3*4+3] = 1.;
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(oglP);
oglM[0*4+0] = 1.;
oglM[1*4+1] = 1.;
oglM[2*4+2] = 1.;
oglM[3*4+3] = 1.;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(oglM);
SetViewportClipping(v, clip);
}
VTKM_CONT_EXPORT
virtual void SetViewportClipping(vtkm::rendering::View &v, bool clip)
{
if (clip)
{
vtkm::Float32 vl, vr, vb, vt;
v.GetRealViewport(vl,vr,vb,vt);
vtkm::Float32 _x = static_cast<vtkm::Float32>(v.Width)*(1.f+vl)/2.f;
vtkm::Float32 _y = static_cast<vtkm::Float32>(v.Height)*(1.f+vb)/2.f;
vtkm::Float32 _w = static_cast<vtkm::Float32>(v.Width)*(vr-vl)/2.f;
vtkm::Float32 _h = static_cast<vtkm::Float32>(v.Height)*(vt-vb)/2.f;
glViewport(static_cast<int>(_x), static_cast<int>(_y),
static_cast<int>(_w), static_cast<int>(_h));
}
else
{
glViewport(0,0, v.Width, v.Height);
}
}
VTKM_CONT_EXPORT
virtual void SaveAs(const std::string &fileName)
{
std::ofstream of(fileName.c_str());
of << "P6" << std::endl
<< this->Width << " " << this->Height <<std::endl
<< 255 << std::endl;
int height = static_cast<int>(this->Height);
for (int yIndex=height-1; yIndex>=0; yIndex--)
for (std::size_t xIndex=0; xIndex < this->Width; xIndex++)
{
const vtkm::Float32 *tuple =
&(this->ColorBuffer[static_cast<std::size_t>(yIndex)*this->Width*4 + xIndex*4]);
of<<(unsigned char)(tuple[0]*255);
of<<(unsigned char)(tuple[1]*255);
of<<(unsigned char)(tuple[2]*255);
}
of.close();
}
VTKM_CONT_EXPORT
virtual void AddLine(vtkm::Float64 x0, vtkm::Float64 y0,
vtkm::Float64 x1, vtkm::Float64 y1,
vtkm::Float32 linewidth,
const vtkm::rendering::Color &c)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glColor3fv(c.Components);
glLineWidth(linewidth);
glBegin(GL_LINES);
glVertex2f(float(x0),float(y0));
glVertex2f(float(x1),float(y1));
glEnd();
}
VTKM_CONT_EXPORT
virtual void AddColorBar(vtkm::Float32 x, vtkm::Float32 y,
vtkm::Float32 w, vtkm::Float32 h,
const vtkm::rendering::ColorTable &ct,
bool horizontal)
{
const int n = 256;
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glBegin(GL_QUADS);
for (int i=0; i<n; i++)
{
vtkm::Float32 v0 = static_cast<vtkm::Float32>(i)/static_cast<vtkm::Float32>(n);
vtkm::Float32 v1 = static_cast<vtkm::Float32>(i+1)/static_cast<vtkm::Float32>(n);
Color c0 = ct.MapRGB(v0);
Color c1 = ct.MapRGB(v1);
if (horizontal)
{
vtkm::Float32 x0 = x + w*v0;
vtkm::Float32 x1 = x + w*v1;
vtkm::Float32 y0 = y;
vtkm::Float32 y1 = y + h;
glColor3fv(c0.Components);
glVertex2f(x0,y0);
glVertex2f(x0,y1);
glColor3fv(c1.Components);
glVertex2f(x1,y1);
glVertex2f(x1,y0);
}
else // vertical
{
vtkm::Float32 x0 = x;
vtkm::Float32 x1 = x + w;
vtkm::Float32 y0 = y + h*v0;
vtkm::Float32 y1 = y + h*v1;
glColor3fv(c0.Components);
glVertex2f(x0,y1);
glVertex2f(x1,y1);
glColor3fv(c1.Components);
glVertex2f(x1,y0);
glVertex2f(x0,y0);
}
}
glEnd();
}
VTKM_CONT_EXPORT
virtual void AddText(vtkm::Float32 x, vtkm::Float32 y,
vtkm::Float32 scale,
vtkm::Float32 angle,
vtkm::Float32 windowaspect,
vtkm::Float32 anchorx, vtkm::Float32 anchory,
Color color,
std::string text)
{
glPushMatrix();
glTranslatef(x,y,0);
glScalef(1.f/windowaspect, 1, 1);
glRotatef(angle, 0,0,1);
glColor3fv(color.Components);
RenderText(scale, anchorx, anchory, text);
glPopMatrix();
}
private:
BitmapFont Font;
TextureGL FontTexture;
void RenderText(vtkm::Float32 scale,
vtkm::Float32 anchorx, vtkm::Float32 anchory,
std::string text)
{
if (this->FontTexture.ID == 0)
{
Font = BitmapFontFactory::CreateLiberation2Sans();
std::vector<unsigned char> &rawpngdata = this->Font.GetRawImageData();
std::vector<unsigned char> rgba;
unsigned long width, height;
int error = decodePNG(rgba, width, height,
&rawpngdata[0], rawpngdata.size());
if (error != 0)
{
return;
}
this->FontTexture.CreateAlphaFromRGBA(int(width),int(height),rgba);
}
VTKM_CONT_EXPORT
virtual void Clear()
this->FontTexture.Enable();
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDisable(GL_LIGHTING);
//glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -.5);
glBegin(GL_QUADS);
vtkm::Float32 textwidth = this->Font.GetTextWidth(text);
vtkm::Float32 fx = -(.5f + .5f*anchorx) * textwidth;
vtkm::Float32 fy = -(.5f + .5f*anchory);
vtkm::Float32 fz = 0;
for (unsigned int i=0; i<text.length(); ++i)
{
glClearColor(this->BackgroundColor.Components[0],
this->BackgroundColor.Components[1],
this->BackgroundColor.Components[2],
1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
VTKM_CONT_EXPORT
virtual void Finish()
{
glFinish();
char c = text[i];
char nextchar = (i < text.length()-1) ? text[i+1] : 0;
vtkm::Float32 vl,vr,vt,vb;
vtkm::Float32 tl,tr,tt,tb;
this->Font.GetCharPolygon(c, fx, fy,
vl, vr, vt, vb,
tl, tr, tt, tb, nextchar);
glTexCoord2f(tl, 1.f-tt);
glVertex3f(scale*vl, scale*vt, fz);
glTexCoord2f(tl, 1.f-tb);
glVertex3f(scale*vl, scale*vb, fz);
glTexCoord2f(tr, 1.f-tb);
glVertex3f(scale*vr, scale*vb, fz);
glTexCoord2f(tr, 1.f-tt);
glVertex3f(scale*vr, scale*vt, fz);
}
VTKM_CONT_EXPORT
virtual void SetViewToWorldSpace(vtkm::rendering::View &v, bool clip)
{
vtkm::Float32 oglP[16], oglM[16];
glEnd();
CreateOGLMatrix(v.CreateProjectionMatrix(), oglP);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(oglP);
CreateOGLMatrix(v.CreateViewMatrix(), oglM);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(oglM);
this->FontTexture.Disable();
SetViewportClipping(v, clip);
}
VTKM_CONT_EXPORT
virtual void SetViewToScreenSpace(vtkm::rendering::View &v, bool clip)
{
vtkm::Float32 oglP[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
vtkm::Float32 oglM[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
oglP[0*4+0] = 1.;
oglP[1*4+1] = 1.;
oglP[2*4+2] = -1.;
oglP[3*4+3] = 1.;
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(oglP);
oglM[0*4+0] = 1.;
oglM[1*4+1] = 1.;
oglM[2*4+2] = 1.;
oglM[3*4+3] = 1.;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(oglM);
SetViewportClipping(v, clip);
}
VTKM_CONT_EXPORT
virtual void SetViewportClipping(vtkm::rendering::View &v, bool clip)
{
if (clip)
{
vtkm::Float32 vl, vr, vb, vt;
v.GetRealViewport(vl,vr,vb,vt);
vtkm::Float32 _x = static_cast<vtkm::Float32>(v.Width)*(1.f+vl)/2.f;
vtkm::Float32 _y = static_cast<vtkm::Float32>(v.Height)*(1.f+vb)/2.f;
vtkm::Float32 _w = static_cast<vtkm::Float32>(v.Width)*(vr-vl)/2.f;
vtkm::Float32 _h = static_cast<vtkm::Float32>(v.Height)*(vt-vb)/2.f;
glViewport(static_cast<int>(_x), static_cast<int>(_y),
static_cast<int>(_w), static_cast<int>(_h));
}
else
{
glViewport(0,0, v.Width, v.Height);
}
}
VTKM_CONT_EXPORT
void CreateOGLMatrix(const vtkm::Matrix<vtkm::Float32,4,4> &mtx,
vtkm::Float32 *oglM)
{
oglM[ 0] = mtx[0][0];
oglM[ 1] = mtx[1][0];
oglM[ 2] = mtx[2][0];
oglM[ 3] = mtx[3][0];
oglM[ 4] = mtx[0][1];
oglM[ 5] = mtx[1][1];
oglM[ 6] = mtx[2][1];
oglM[ 7] = mtx[3][1];
oglM[ 8] = mtx[0][2];
oglM[ 9] = mtx[1][2];
oglM[10] = mtx[2][2];
oglM[11] = mtx[3][2];
oglM[12] = mtx[0][3];
oglM[13] = mtx[1][3];
oglM[14] = mtx[2][3];
oglM[15] = mtx[3][3];
}
VTKM_CONT_EXPORT
virtual void SaveAs(const std::string &fileName)
{
std::ofstream of(fileName.c_str());
of << "P6" << std::endl
<< this->Width << " " << this->Height <<std::endl
<< 255 << std::endl;
int height = static_cast<int>(this->Height);
for (int yIndex=height-1; yIndex>=0; yIndex--)
for (std::size_t xIndex=0; xIndex < this->Width; xIndex++)
{
const vtkm::Float32 *tuple =
&(this->ColorBuffer[static_cast<std::size_t>(yIndex)*this->Width*4 + xIndex*4]);
of<<(unsigned char)(tuple[0]*255);
of<<(unsigned char)(tuple[1]*255);
of<<(unsigned char)(tuple[2]*255);
}
of.close();
}
VTKM_CONT_EXPORT
virtual void AddLine(vtkm::Float64 x0, vtkm::Float64 y0,
vtkm::Float64 x1, vtkm::Float64 y1,
vtkm::Float32 linewidth,
const vtkm::rendering::Color &c)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glColor3fv(c.Components);
glLineWidth(linewidth);
glBegin(GL_LINES);
glVertex2f(float(x0),float(y0));
glVertex2f(float(x1),float(y1));
glEnd();
}
virtual void AddColorBar(vtkm::Float32 x, vtkm::Float32 y,
vtkm::Float32 w, vtkm::Float32 h,
const vtkm::rendering::ColorTable &ct,
bool horizontal)
{
const int n = 256;
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glBegin(GL_QUADS);
for (int i=0; i<n; i++)
{
vtkm::Float32 v0 = static_cast<vtkm::Float32>(i)/static_cast<vtkm::Float32>(n);
vtkm::Float32 v1 = static_cast<vtkm::Float32>(i+1)/static_cast<vtkm::Float32>(n);
Color c0 = ct.MapRGB(v0);
Color c1 = ct.MapRGB(v1);
if (horizontal)
{
vtkm::Float32 x0 = x + w*v0;
vtkm::Float32 x1 = x + w*v1;
vtkm::Float32 y0 = y;
vtkm::Float32 y1 = y + h;
glColor3fv(c0.Components);
glVertex2f(x0,y0);
glVertex2f(x0,y1);
glColor3fv(c1.Components);
glVertex2f(x1,y1);
glVertex2f(x1,y0);
}
else // vertical
{
vtkm::Float32 x0 = x;
vtkm::Float32 x1 = x + w;
vtkm::Float32 y0 = y + h*v0;
vtkm::Float32 y1 = y + h*v1;
glColor3fv(c0.Components);
glVertex2f(x0,y1);
glVertex2f(x1,y1);
glColor3fv(c1.Components);
glVertex2f(x1,y0);
glVertex2f(x0,y0);
}
}
glEnd();
}
//glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0);
glDepthMask(GL_TRUE);
glDisable(GL_ALPHA_TEST);
}
};
}} //namespace vtkm::rendering

@ -36,54 +36,56 @@ namespace rendering {
class RenderSurfaceGLX : public RenderSurfaceGL
{
public:
VTKM_CONT_EXPORT
RenderSurfaceGLX(std::size_t w=1024, std::size_t h=1024,
const vtkm::rendering::Color &c=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: RenderSurfaceGL(w,h,c)
{
ctx = NULL;
}
VTKM_CONT_EXPORT
RenderSurfaceGLX(std::size_t w=1024, std::size_t h=1024,
const vtkm::rendering::Color &c=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: RenderSurfaceGL(w,h,c)
{
ctx = NULL;
}
VTKM_CONT_EXPORT
virtual void Initialize()
{
ctx = glXGetCurrentContext();
if (!ctx)
throw vtkm::cont::ErrorControlBadValue("GL context creation failed.");
rgba.resize(width*height*4);
/*
if (!OSMesaMakeCurrent(ctx, &rgba[0], GL_FLOAT, static_cast<GLsizei>(width), static_cast<GLsizei>(height)))
throw vtkm::cont::ErrorControlBadValue("OSMesa context activation failed.");
*/
VTKM_CONT_EXPORT
virtual void Initialize()
{
ctx = glXGetCurrentContext();
if (!ctx)
throw vtkm::cont::ErrorControlBadValue("GL context creation failed.");
/*
rgba.resize(width*height*4);
if (!OSMesaMakeCurrent(ctx, &rgba[0], GL_FLOAT, static_cast<GLsizei>(width), static_cast<GLsizei>(height)))
throw vtkm::cont::ErrorControlBadValue("OSMesa context activation failed.");
*/
glEnable(GL_DEPTH_TEST);
}
glEnable(GL_DEPTH_TEST);
}
VTKM_CONT_EXPORT
virtual void Clear()
{
glClearColor(bgColor.Components[0],bgColor.Components[1],bgColor.Components[2], 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
VTKM_CONT_EXPORT
virtual void Finish()
{
RenderSurfaceGL::Finish();
VTKM_CONT_EXPORT
virtual void Clear()
{
glClearColor(this->BackgroundColor.Components[0],
this->BackgroundColor.Components[1],
this->BackgroundColor.Components[2], 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
VTKM_CONT_EXPORT
virtual void Finish()
{
RenderSurfaceGL::Finish();
/* TODO
//Copy zbuff into floating point array.
unsigned int *raw_zbuff;
int zbytes, w, h;
GLboolean ret;
ret = OSMesaGetDepthBuffer(ctx, &w, &h, &zbytes, (void**)&raw_zbuff);
if (!ret || static_cast<std::size_t>(w)!=width || static_cast<std::size_t>(h)!=height)
throw vtkm::cont::ErrorControlBadValue("Wrong width/height in ZBuffer");
std::size_t npixels = width*height;
for (std::size_t i=0; i<npixels; i++)
zbuff[i] = float(raw_zbuff[i]) / float(UINT_MAX);
*/
}
/* TODO
//Copy zbuff into floating point array.
unsigned int *raw_zbuff;
int zbytes, w, h;
GLboolean ret;
ret = OSMesaGetDepthBuffer(ctx, &w, &h, &zbytes, (void**)&raw_zbuff);
if (!ret || static_cast<std::size_t>(w)!=width || static_cast<std::size_t>(h)!=height)
throw vtkm::cont::ErrorControlBadValue("Wrong width/height in ZBuffer");
std::size_t npixels = width*height;
for (std::size_t i=0; i<npixels; i++)
zbuff[i] = float(raw_zbuff[i]) / float(UINT_MAX);
*/
}
private:
GLXContext ctx;

@ -36,64 +36,64 @@ namespace rendering {
class RenderSurfaceOSMesa : public RenderSurfaceGL
{
public:
VTKM_CONT_EXPORT
RenderSurfaceOSMesa(std::size_t w=1024, std::size_t h=1024,
const vtkm::rendering::Color &c=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: RenderSurfaceGL(w,h,c)
VTKM_CONT_EXPORT
RenderSurfaceOSMesa(std::size_t w=1024, std::size_t h=1024,
const vtkm::rendering::Color &c=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: RenderSurfaceGL(w,h,c)
{
ctx = NULL;
}
VTKM_CONT_EXPORT
virtual void Initialize()
{
ctx = OSMesaCreateContextExt(OSMESA_RGBA, 32, 0, 0, NULL);
if (!ctx)
throw vtkm::cont::ErrorControlBadValue("OSMesa context creation failed.");
this->ColorBuffer.resize(this->Width*this->Height*4);
if (!OSMesaMakeCurrent(ctx,
&this->ColorBuffer[0],
GL_FLOAT,
static_cast<GLsizei>(this->Width),
static_cast<GLsizei>(this->Height)))
{
ctx = NULL;
throw vtkm::cont::ErrorControlBadValue("OSMesa context activation failed.");
}
VTKM_CONT_EXPORT
virtual void Initialize()
{
ctx = OSMesaCreateContextExt(OSMESA_RGBA, 32, 0, 0, NULL);
if (!ctx)
throw vtkm::cont::ErrorControlBadValue("OSMesa context creation failed.");
this->ColorBuffer.resize(this->Width*this->Height*4);
if (!OSMesaMakeCurrent(ctx,
&this->ColorBuffer[0],
GL_FLOAT,
static_cast<GLsizei>(this->Width),
static_cast<GLsizei>(this->Height)))
{
throw vtkm::cont::ErrorControlBadValue("OSMesa context activation failed.");
}
glEnable(GL_DEPTH_TEST);
}
glEnable(GL_DEPTH_TEST);
}
VTKM_CONT_EXPORT
virtual void Clear()
{
glClearColor(this->BackgroundColor.Components[0],
this->BackgroundColor.Components[1],
this->BackgroundColor.Components[2],
1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
VTKM_CONT_EXPORT
virtual void Finish()
{
RenderSurfaceGL::Finish();
VTKM_CONT_EXPORT
virtual void Clear()
//Copy zbuff into floating point array.
unsigned int *raw_zbuff;
int zbytes, w, h;
GLboolean ret;
ret = OSMesaGetDepthBuffer(ctx, &w, &h, &zbytes, (void**)&raw_zbuff);
if (!ret ||
static_cast<std::size_t>(w)!=this->Width ||
static_cast<std::size_t>(h)!=this->Height)
{
glClearColor(this->BackgroundColor.Components[0],
this->BackgroundColor.Components[1],
this->BackgroundColor.Components[2],
1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
throw vtkm::cont::ErrorControlBadValue("Wrong width/height in ZBuffer");
}
VTKM_CONT_EXPORT
virtual void Finish()
std::size_t npixels = this->Width*this->Height;
for (std::size_t i=0; i<npixels; i++)
{
RenderSurfaceGL::Finish();
//Copy zbuff into floating point array.
unsigned int *raw_zbuff;
int zbytes, w, h;
GLboolean ret;
ret = OSMesaGetDepthBuffer(ctx, &w, &h, &zbytes, (void**)&raw_zbuff);
if (!ret ||
static_cast<std::size_t>(w)!=this->Width ||
static_cast<std::size_t>(h)!=this->Height)
{
throw vtkm::cont::ErrorControlBadValue("Wrong width/height in ZBuffer");
}
std::size_t npixels = this->Width*this->Height;
for (std::size_t i=0; i<npixels; i++)
{
this->DepthBuffer[i] = float(raw_zbuff[i]) / float(UINT_MAX);
}
this->DepthBuffer[i] = float(raw_zbuff[i]) / float(UINT_MAX);
}
}
private:
OSMesaContext ctx;

@ -36,77 +36,77 @@ namespace rendering {
class RenderSurfaceRayTracer : public RenderSurface
{
public:
VTKM_CONT_EXPORT
RenderSurfaceRayTracer(std::size_t width=1024, std::size_t height=1024,
const vtkm::rendering::Color &color=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: RenderSurface(width,height,color)
{
this->ColorArray = vtkm::cont::make_ArrayHandle(this->ColorBuffer);
this->DepthArray = vtkm::cont::make_ArrayHandle(this->DepthBuffer);
}
VTKM_CONT_EXPORT
RenderSurfaceRayTracer(std::size_t width=1024, std::size_t height=1024,
const vtkm::rendering::Color &color=vtkm::rendering::Color(0.0f,0.0f,0.0f,1.0f))
: RenderSurface(width,height,color)
{
this->ColorArray = vtkm::cont::make_ArrayHandle(this->ColorBuffer);
this->DepthArray = vtkm::cont::make_ArrayHandle(this->DepthBuffer);
}
class ClearBuffers : public vtkm::worklet::WorkletMapField
{
vtkm::rendering::Color ClearColor;
vtkm::Id NumPixels;
public:
VTKM_CONT_EXPORT
ClearBuffers(const vtkm::rendering::Color &clearColor,
vtkm::Id numPixels)
class ClearBuffers : public vtkm::worklet::WorkletMapField
{
vtkm::rendering::Color ClearColor;
vtkm::Id NumPixels;
public:
VTKM_CONT_EXPORT
ClearBuffers(const vtkm::rendering::Color &clearColor,
vtkm::Id numPixels)
: ClearColor(clearColor),
NumPixels(numPixels)
{}
typedef void ControlSignature(FieldOut<>,
ExecObject);
typedef void ExecutionSignature(_1,
_2,
WorkIndex);
VTKM_EXEC_EXPORT
void operator()(vtkm::Float32 &depth,
vtkm::exec::ExecutionWholeArray<vtkm::Float32> &colorBuffer,
const vtkm::Id &index) const
{}
typedef void ControlSignature(FieldOut<>,
ExecObject);
typedef void ExecutionSignature(_1,
_2,
WorkIndex);
VTKM_EXEC_EXPORT
void operator()(vtkm::Float32 &depth,
vtkm::exec::ExecutionWholeArray<vtkm::Float32> &colorBuffer,
const vtkm::Id &index) const
{
if(index >= NumPixels) return;
depth = 1.001f;
vtkm::Id offset = index * 4;
colorBuffer.Set(offset + 0, ClearColor.Components[0]);
colorBuffer.Set(offset + 1, ClearColor.Components[1]);
colorBuffer.Set(offset + 2, ClearColor.Components[2]);
colorBuffer.Set(offset + 3, ClearColor.Components[3]);
}
}; //class ClearBuffers
VTKM_CONT_EXPORT
virtual void SaveAs(const std::string &fileName)
{
std::ofstream of(fileName.c_str());
of<<"P6"<<std::endl<<this->Width<<" "<<this->Height<<std::endl<<255<<std::endl;
int height = static_cast<int>(this->Height);
for (int yIndex=height-1; yIndex>=0; yIndex--)
for (std::size_t xIndex=0; xIndex < this->Width; xIndex++)
{
if(index >= NumPixels) return;
depth = 1.001f;
vtkm::Id offset = index * 4;
colorBuffer.Set(offset + 0, ClearColor.Components[0]);
colorBuffer.Set(offset + 1, ClearColor.Components[1]);
colorBuffer.Set(offset + 2, ClearColor.Components[2]);
colorBuffer.Set(offset + 3, ClearColor.Components[3]);
const vtkm::Float32 *tuple =
&(this->ColorBuffer[static_cast<std::size_t>(yIndex)*this->Width*4 + xIndex*4]);
of<<(unsigned char)(tuple[0]*255);
of<<(unsigned char)(tuple[1]*255);
of<<(unsigned char)(tuple[2]*255);
}
}; //class ClearBuffers
of.close();
}
VTKM_CONT_EXPORT
virtual void Clear()
{
this->ColorArray = vtkm::cont::make_ArrayHandle(this->ColorBuffer);
this->DepthArray = vtkm::cont::make_ArrayHandle(this->DepthBuffer);
vtkm::worklet::DispatcherMapField< ClearBuffers >(
ClearBuffers( this->BackgroundColor,
static_cast<vtkm::Int32>(this->Width*this->Height) ) )
.Invoke( this->DepthArray,
vtkm::exec::ExecutionWholeArray<vtkm::Float32>(this->ColorArray) );
}
VTKM_CONT_EXPORT
virtual void SaveAs(const std::string &fileName)
{
std::ofstream of(fileName.c_str());
of<<"P6"<<std::endl<<this->Width<<" "<<this->Height<<std::endl<<255<<std::endl;
int height = static_cast<int>(this->Height);
for (int yIndex=height-1; yIndex>=0; yIndex--)
for (std::size_t xIndex=0; xIndex < this->Width; xIndex++)
{
const vtkm::Float32 *tuple =
&(this->ColorBuffer[static_cast<std::size_t>(yIndex)*this->Width*4 + xIndex*4]);
of<<(unsigned char)(tuple[0]*255);
of<<(unsigned char)(tuple[1]*255);
of<<(unsigned char)(tuple[2]*255);
}
of.close();
}
VTKM_CONT_EXPORT
virtual void Clear()
{
this->ColorArray = vtkm::cont::make_ArrayHandle(this->ColorBuffer);
this->DepthArray = vtkm::cont::make_ArrayHandle(this->DepthBuffer);
vtkm::worklet::DispatcherMapField< ClearBuffers >(
ClearBuffers( this->BackgroundColor,
static_cast<vtkm::Int32>(this->Width*this->Height) ) )
.Invoke( this->DepthArray,
vtkm::exec::ExecutionWholeArray<vtkm::Float32>(this->ColorArray) );
}
vtkm::cont::ArrayHandle<vtkm::Float32> ColorArray;
vtkm::cont::ArrayHandle<vtkm::Float32> DepthArray;
vtkm::cont::ArrayHandle<vtkm::Float32> ColorArray;
vtkm::cont::ArrayHandle<vtkm::Float32> DepthArray;
};

@ -31,12 +31,8 @@ class Scene
{
public:
std::vector<vtkm::rendering::Plot> Plots;
};
class Scene3D : public Scene
{
public:
Scene3D() {}
Scene() {}
template<typename SceneRendererType, typename SurfaceType>
VTKM_CONT_EXPORT
@ -68,26 +64,6 @@ protected:
vtkm::Bounds SpatialBounds;
};
class Scene2D : public Scene
{
public:
Scene2D() {}
template<typename SceneRendererType, typename SurfaceType>
VTKM_CONT_EXPORT
void Render(SceneRendererType &sceneRenderer,
SurfaceType &surface,
vtkm::rendering::View &view)
{
for (std::size_t i = 0; i < this->Plots.size(); i++)
{
sceneRenderer.StartScene();
this->Plots[i].Render(sceneRenderer, surface, view);
sceneRenderer.EndScene();
}
}
};
}} //namespace vtkm::rendering
#endif //vtk_m_rendering_Scene_h

@ -0,0 +1,248 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_TextAnnotation_h
#define vtk_m_rendering_TextAnnotation_h
#include <vtkm/cont/DataSet.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/View.h>
#include <vtkm/rendering/RenderSurface.h>
namespace vtkm {
namespace rendering {
class TextAnnotation
{
public:
enum HorizontalAlignment
{
Left,
HCenter,
Right
};
enum VerticalAlignment
{
Bottom,
VCenter,
Top
};
protected:
std::string Text;
Color TextColor;
vtkm::Float32 Scale;
vtkm::Float32 AnchorX, AnchorY;
public:
TextAnnotation(const std::string &txt, Color c, vtkm::Float32 s)
: Text(txt), TextColor(c), Scale(s)
{
// default anchor: bottom-left
AnchorX = -1;
AnchorY = -1;
}
virtual ~TextAnnotation()
{
}
void SetText(const std::string &txt)
{
Text = txt;
}
void SetRawAnchor(vtkm::Float32 h, vtkm::Float32 v)
{
AnchorX = h;
AnchorY = v;
}
void SetAlignment(HorizontalAlignment h, VerticalAlignment v)
{
switch (h)
{
case Left: AnchorX = -1.0f; break;
case HCenter: AnchorX = 0.0f; break;
case Right: AnchorX = +1.0f; break;
}
// For vertical alignment, "center" is generally the center
// of only the above-baseline contents of the font, so we
// use a value slightly off of zero for VCenter.
// (We don't use an offset value instead of -1.0 for the
// bottom value, because generally we want a true minimum
// extent, e.g. to have text sitting at the bottom of a
// window, and in that case, we need to keep all the text,
// including parts that descend below the baseline, above
// the bottom of the window.
switch (v)
{
case Bottom: AnchorY = -1.0f; break;
case VCenter: AnchorY = -0.06f; break;
case Top: AnchorY = +1.0f; break;
}
}
void SetScale(vtkm::Float32 s)
{
Scale = s;
}
virtual void Render(View &view,
WorldAnnotator &worldAnnotator,
RenderSurface &renderSurface) = 0;
};
class ScreenTextAnnotation : public TextAnnotation
{
protected:
vtkm::Float32 XPos,YPos;
vtkm::Float32 Angle;
public:
ScreenTextAnnotation(const std::string &txt, Color c, vtkm::Float32 s,
vtkm::Float32 ox, vtkm::Float32 oy, vtkm::Float32 angleDeg = 0.)
: TextAnnotation(txt,c,s)
{
XPos = ox;
YPos = oy;
Angle = angleDeg;
}
void SetPosition(vtkm::Float32 ox, vtkm::Float32 oy)
{
XPos = ox;
YPos = oy;
}
virtual void Render(View &view,
WorldAnnotator &,
RenderSurface &renderSurface)
{
vtkm::Float32 WindowAspect = vtkm::Float32(view.Width) /
vtkm::Float32(view.Height);
renderSurface.AddText(XPos,YPos,
Scale,
Angle,
WindowAspect,
AnchorX, AnchorY,
TextColor, Text);
}
};
class BillboardTextAnnotation : public TextAnnotation
{
protected:
vtkm::Float32 XPos,YPos,ZPos;
vtkm::Float32 Angle;
public:
BillboardTextAnnotation(const std::string &txt, Color c, vtkm::Float32 s,
vtkm::Float32 ox, vtkm::Float32 oy, vtkm::Float32 oz,
vtkm::Float32 angleDeg = 0.)
: TextAnnotation(txt,c,s)
{
XPos = ox;
YPos = oy;
ZPos = oz;
Angle = angleDeg;
}
void SetPosition(vtkm::Float32 ox, vtkm::Float32 oy, vtkm::Float32 oz)
{
XPos = ox;
YPos = oy;
ZPos = oz;
}
virtual void Render(View &view,
WorldAnnotator &worldAnnotator,
RenderSurface &renderSurface)
{
vtkm::Matrix<vtkm::Float32, 4, 4> V, P;
V = view.CreateViewMatrix();
P = view.CreateProjectionMatrix();
vtkm::Vec<vtkm::Float32,4> p4w(XPos,YPos,ZPos,1);
vtkm::Vec<vtkm::Float32,4> p4s =
vtkm::MatrixMultiply(vtkm::MatrixMultiply(P,V), p4w);
renderSurface.SetViewToScreenSpace(view,true);
vtkm::Float32 psx = p4s[0] / p4s[3];
vtkm::Float32 psy = p4s[1] / p4s[3];
vtkm::Float32 psz = p4s[2] / p4s[3];
vtkm::Matrix<vtkm::Float32, 4, 4> T;
T = MatrixHelpers::TranslateMatrix(psx,psy,-psz);
vtkm::Float32 WindowAspect =
vtkm::Float32(view.Width) / vtkm::Float32(view.Height);
vtkm::Matrix<vtkm::Float32, 4, 4> SW;
SW = MatrixHelpers::ScaleMatrix(1.f/WindowAspect, 1, 1);
vtkm::Matrix<vtkm::Float32, 4, 4> SV;
vtkm::MatrixIdentity(SV);
//if view type == 2D?
{
vtkm::Float32 vl, vr, vb, vt;
view.GetRealViewport(vl,vr,vb,vt);
vtkm::Float32 xs = (vr-vl);
vtkm::Float32 ys = (vt-vb);
SV = MatrixHelpers::ScaleMatrix(2.f/xs, 2.f/ys, 1);
}
vtkm::Matrix<vtkm::Float32, 4, 4> R;
R = MatrixHelpers::RotateZMatrix(Angle * 3.14159265f / 180.f);
vtkm::Vec<vtkm::Float32,4> origin4(0,0,0,1);
vtkm::Vec<vtkm::Float32,4> right4(1,0,0,0);
vtkm::Vec<vtkm::Float32,4> up4(0,1,0,0);
vtkm::Matrix<vtkm::Float32, 4, 4> M =
vtkm::MatrixMultiply(T,
vtkm::MatrixMultiply(SW,
vtkm::MatrixMultiply(SV,
R)));
vtkm::Vec<vtkm::Float32,4> new_origin4 =
vtkm::MatrixMultiply(M, origin4);
vtkm::Vec<vtkm::Float32,4> new_right4 =
vtkm::MatrixMultiply(M, right4);
vtkm::Vec<vtkm::Float32,4> new_up4 =
vtkm::MatrixMultiply(M, up4);
vtkm::Float32 px = new_origin4[0] / new_origin4[3];
vtkm::Float32 py = new_origin4[1] / new_origin4[3];
vtkm::Float32 pz = new_origin4[2] / new_origin4[3];
vtkm::Float32 rx = new_right4[0];
vtkm::Float32 ry = new_right4[1];
vtkm::Float32 rz = new_right4[2];
vtkm::Float32 ux = new_up4[0];
vtkm::Float32 uy = new_up4[1];
vtkm::Float32 uz = new_up4[2];
worldAnnotator.AddText(px,py,pz,
rx,ry,rz,
ux,uy,uz,
Scale,
AnchorX, AnchorY,
TextColor, Text);
renderSurface.SetViewToWorldSpace(view,true);
}
};
}} //namespace vtkm::rendering
#endif //vtk_m_rendering_TextAnnotation_h

147
vtkm/rendering/TextureGL.h Normal file

@ -0,0 +1,147 @@
//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 Sandia Corporation.
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//
//=============================================================================
#ifndef vtk_m_TextureGL_h
#define vtk_m_TextureGL_h
#include <GL/gl.h>
#include <vtkm/rendering/ColorTable.h>
#include <vector>
namespace vtkm {
namespace rendering {
class TextureGL
{
public:
GLuint ID;
int Dimension;
bool MIPMap;
bool Linear2D;
bool LinearMIP;
public:
TextureGL()
{
this->ID = 0;
this->Dimension = 0;
this->MIPMap = false;
this->Linear2D = true;
this->LinearMIP = true;
}
void Enable()
{
if (this->ID == 0)
return;
if (this->Dimension == 1)
{
// no this->MIPMapping for 1D (at the moment)
glBindTexture(GL_TEXTURE_1D, this->ID);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
if (this->Linear2D)
{
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glEnable(GL_TEXTURE_1D);
}
else if (this->Dimension == 2)
{
glBindTexture(GL_TEXTURE_2D, this->ID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
if (this->Linear2D)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (!this->MIPMap)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
else if (this->LinearMIP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (!this->MIPMap)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
else if (this->LinearMIP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
}
glEnable(GL_TEXTURE_2D);
}
}
void Disable()
{
if (this->Dimension == 1)
glDisable(GL_TEXTURE_1D);
else if (this->Dimension == 2)
glDisable(GL_TEXTURE_2D);
}
void CreateAlphaFromRGBA(int w, int h, std::vector<unsigned char> &rgba)
{
this->Dimension = 2;
std::vector<unsigned char> alpha(rgba.size()/4);
for (unsigned int i=0; i<alpha.size(); i++)
{
alpha[i] = rgba[i*4+3];
}
if (this->ID == 0)
{
glGenTextures(1, &this->ID);
}
if (this->Dimension == 1)
{
glBindTexture(GL_TEXTURE_1D, this->ID);
}
else if (this->Dimension == 2)
{
glBindTexture(GL_TEXTURE_2D, this->ID);
//#define HW_MIPMAPS
#ifdef HW_MIPMAPS
mpimap = true;
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
#endif
glTexImage2D(GL_TEXTURE_2D, 0,
GL_ALPHA,
w, h,
0,
GL_ALPHA,
GL_UNSIGNED_BYTE,
(void*)(&(alpha[0])));
}
}
};
}} //namespace vtkm::rendering
#endif //vtk_m_rendering_TextureGL_h

@ -108,67 +108,67 @@ public:
void operator()(const CellNodeVecType &cellIndices,
const vtkm::Id &cellIndex) const
{
vtkm::Vec<vtkm::Id,4> triangle;
if (DIM == 2)
{
const vtkm::Id triangleOffset = cellIndex * 2;
// 0-1-2
triangle[1] = cellIndices[0];
triangle[2] = cellIndices[1];
triangle[3] = cellIndices[2];
triangle[0] = cellIndex;
OutputIndices.Set(triangleOffset, triangle);
// 0-3-2
triangle[2] = cellIndices[3];
OutputIndices.Set(triangleOffset+1, triangle);
}
else if (DIM == 3)
{
const vtkm::Id triangleOffset = cellIndex * 12;
// 0-1-2
triangle[1] = cellIndices[0];
triangle[2] = cellIndices[1];
triangle[3] = cellIndices[2];
triangle[0] = cellIndex;
OutputIndices.Set(triangleOffset, triangle);
// 0-3-2
triangle[2] = cellIndices[3];
OutputIndices.Set(triangleOffset+1, triangle);
// 0-3-7
triangle[3] = cellIndices[7];
OutputIndices.Set(triangleOffset+2, triangle);
// 0-4-7
triangle[2] = cellIndices[4];
OutputIndices.Set(triangleOffset+3, triangle);
// 5-4-7
triangle[1] = cellIndices[5];
OutputIndices.Set(triangleOffset+4, triangle);
// 5-6-7
triangle[2] = cellIndices[6];
OutputIndices.Set(triangleOffset+5, triangle);
// 3-6-7
triangle[1] = cellIndices[3];
OutputIndices.Set(triangleOffset+6, triangle);
// 3-6-2
triangle[3] = cellIndices[2];
OutputIndices.Set(triangleOffset+7, triangle);
// 1-6-2
triangle[1] = cellIndices[1];
OutputIndices.Set(triangleOffset+8, triangle);
// 1-6-5
triangle[3] = cellIndices[5];
OutputIndices.Set(triangleOffset+9, triangle);
// 1-4-5
triangle[2] = cellIndices[4];
OutputIndices.Set(triangleOffset+10, triangle);
// 1-4-0
triangle[3] = cellIndices[0];
OutputIndices.Set(triangleOffset+11, triangle);
}
else
{
throw vtkm::cont::ErrorControlBadType("Unsupported dimension for structured trianglulation");
}
vtkm::Vec<vtkm::Id,4> triangle;
if (DIM == 2)
{
const vtkm::Id triangleOffset = cellIndex * 2;
// 0-1-2
triangle[1] = cellIndices[0];
triangle[2] = cellIndices[1];
triangle[3] = cellIndices[2];
triangle[0] = cellIndex;
OutputIndices.Set(triangleOffset, triangle);
// 0-3-2
triangle[2] = cellIndices[3];
OutputIndices.Set(triangleOffset+1, triangle);
}
else if (DIM == 3)
{
const vtkm::Id triangleOffset = cellIndex * 12;
// 0-1-2
triangle[1] = cellIndices[0];
triangle[2] = cellIndices[1];
triangle[3] = cellIndices[2];
triangle[0] = cellIndex;
OutputIndices.Set(triangleOffset, triangle);
// 0-3-2
triangle[2] = cellIndices[3];
OutputIndices.Set(triangleOffset+1, triangle);
// 0-3-7
triangle[3] = cellIndices[7];
OutputIndices.Set(triangleOffset+2, triangle);
// 0-4-7
triangle[2] = cellIndices[4];
OutputIndices.Set(triangleOffset+3, triangle);
// 5-4-7
triangle[1] = cellIndices[5];
OutputIndices.Set(triangleOffset+4, triangle);
// 5-6-7
triangle[2] = cellIndices[6];
OutputIndices.Set(triangleOffset+5, triangle);
// 3-6-7
triangle[1] = cellIndices[3];
OutputIndices.Set(triangleOffset+6, triangle);
// 3-6-2
triangle[3] = cellIndices[2];
OutputIndices.Set(triangleOffset+7, triangle);
// 1-6-2
triangle[1] = cellIndices[1];
OutputIndices.Set(triangleOffset+8, triangle);
// 1-6-5
triangle[3] = cellIndices[5];
OutputIndices.Set(triangleOffset+9, triangle);
// 1-4-5
triangle[2] = cellIndices[4];
OutputIndices.Set(triangleOffset+10, triangle);
// 1-4-0
triangle[3] = cellIndices[0];
OutputIndices.Set(triangleOffset+11, triangle);
}
else
{
throw vtkm::cont::ErrorControlBadType("Unsupported dimension for structured trianglulation");
}
}
};
@ -540,7 +540,7 @@ public:
vtkm::Id shapeTypeAsId = cellSetSingleType.GetCellShape(0);
if(shapeTypeAsId == vtkm::CellShapeTagTriangle::Id)
{
{
//generate the outputIndices
vtkm::Id totalTriangles = cellSetSingleType.GetNumberOfCells();
vtkm::cont::ArrayHandleCounting<vtkm::Id> cellIdxs(0,1,totalTriangles);
@ -549,16 +549,16 @@ public:
vtkm::worklet::DispatcherMapField<Trianglulate>( Trianglulate(outputIndices,
cellSetSingleType.GetConnectivityArray( PointTag(), CellTag() ),
totalTriangles) )
.Invoke(cellSetSingleType.GetShapesArray( PointTag(), CellTag() ),
cellSetSingleType.GetIndexOffsetArray( PointTag(), CellTag()),
cellIdxs );
.Invoke(cellSetSingleType.GetShapesArray( PointTag(), CellTag() ),
cellSetSingleType.GetIndexOffsetArray( PointTag(), CellTag()),
cellIdxs );
outputTriangles = totalTriangles;
}
}
else
{
{
throw vtkm::cont::ErrorControlBadType("Unsupported cell type for trianglulation with CellSetSingleType");
}
}
}
else
{

@ -22,6 +22,7 @@
#include <vtkm/Math.h>
#include <vtkm/Matrix.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/rendering/MatrixHelpers.h>
namespace vtkm {
namespace rendering {
@ -38,7 +39,7 @@ class View
VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> CreateViewMatrix()
{
return View::ViewMatrix(this->Position, this->LookAt, this->Up);
return MatrixHelpers::ViewMatrix(this->Position, this->LookAt, this->Up);
}
VTKM_CONT_EXPORT
@ -69,8 +70,8 @@ class View
matrix(3,3) = 0.f;
vtkm::Matrix<vtkm::Float32,4,4> T, Z;
T = View::TranslateMatrix(this->XPan, this->YPan, 0);
Z = View::ScaleMatrix(this->Zoom, this->Zoom, 1);
T = MatrixHelpers::TranslateMatrix(this->XPan, this->YPan, 0);
Z = MatrixHelpers::ScaleMatrix(this->Zoom, this->Zoom, 1);
matrix = vtkm::MatrixMultiply(Z, vtkm::MatrixMultiply(T, matrix));
return matrix;
}
@ -101,7 +102,7 @@ class View
vtkm::Vec<vtkm::Float32,3> position = lookAt;
position[2] = 1.f;
vtkm::Vec<vtkm::Float32,3> up(0,1,0);
return View::ViewMatrix(position, lookAt, up);
return MatrixHelpers::ViewMatrix(position, lookAt, up);
}
VTKM_CONT_EXPORT
@ -133,144 +134,6 @@ class View
vtkm::Float32 XScale;
};
private:
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> ViewMatrix(const vtkm::Vec<vtkm::Float32,3> &position,
const vtkm::Vec<vtkm::Float32,3> &lookAt,
const vtkm::Vec<vtkm::Float32,3> &up)
{
vtkm::Vec<vtkm::Float32,3> viewDir = position-lookAt;
vtkm::Vec<vtkm::Float32,3> right = vtkm::Cross(up,viewDir);
vtkm::Vec<vtkm::Float32,3> ru = vtkm::Cross(viewDir,right);
vtkm::Normalize(viewDir);
vtkm::Normalize(right);
vtkm::Normalize(ru);
vtkm::Matrix<vtkm::Float32,4,4> matrix;
vtkm::MatrixIdentity(matrix);
matrix(0,0) = right[0];
matrix(0,1) = right[1];
matrix(0,2) = right[2];
matrix(1,0) = ru[0];
matrix(1,1) = ru[1];
matrix(1,2) = ru[2];
matrix(2,0) = viewDir[0];
matrix(2,1) = viewDir[1];
matrix(2,2) = viewDir[2];
matrix(0,3) = -vtkm::dot(right,position);
matrix(1,3) = -vtkm::dot(ru,position);
matrix(2,3) = -vtkm::dot(viewDir,position);
return matrix;
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> ScaleMatrix(const vtkm::Vec<vtkm::Float32,3> &v)
{
return ScaleMatrix(v[0], v[1], v[2]);
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> ScaleMatrix(const vtkm::Float32 &s)
{
return ScaleMatrix(s,s,s);
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> ScaleMatrix(const vtkm::Float32 &x,
const vtkm::Float32 &y,
const vtkm::Float32 &z)
{
vtkm::Matrix<vtkm::Float32,4,4> scaleMatrix(0.0f);
scaleMatrix(0,0) = x;
scaleMatrix(1,1) = y;
scaleMatrix(2,2) = z;
scaleMatrix(3,3) = 1.0f;
return scaleMatrix;
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> TranslateMatrix(const vtkm::Vec<vtkm::Float32,3> &v)
{
return TranslateMatrix(v[0], v[1], v[2]);
}
static VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4> TranslateMatrix(const vtkm::Float32 &x,
const vtkm::Float32 &y,
const vtkm::Float32 &z)
{
vtkm::Matrix<vtkm::Float32,4,4> translateMatrix;
vtkm::MatrixIdentity(translateMatrix);
translateMatrix(0,3) = x;
translateMatrix(1,3) = y;
translateMatrix(2,3) = z;
return translateMatrix;
}
VTKM_CONT_EXPORT
vtkm::Matrix<vtkm::Float32,4,4>
CreateTrackball(vtkm::Float32 p1x, vtkm::Float32 p1y, vtkm::Float32 p2x, vtkm::Float32 p2y)
{
const vtkm::Float32 RADIUS = 0.80f; //z value lookAt x = y = 0.0
const vtkm::Float32 COMPRESSION = 3.5f; // multipliers for x and y.
const vtkm::Float32 AR3 = RADIUS*RADIUS*RADIUS;
vtkm::Matrix<vtkm::Float32,4,4> matrix;
vtkm::MatrixIdentity(matrix);
if (p1x==p2x && p1y==p2y) { return matrix; }
vtkm::Vec<vtkm::Float32, 3> p1(p1x,p1y, AR3/((p1x*p1x+p1y*p1y)*COMPRESSION+AR3));
vtkm::Vec<vtkm::Float32, 3> p2(p2x,p2y, AR3/((p2x*p2x+p2y*p2y)*COMPRESSION+AR3));
vtkm::Vec<vtkm::Float32, 3> axis = vtkm::Normal(vtkm::Cross(p2,p1));
//std::cout<<"Axis: "<<axis[0]<<" "<<axis[1]<<" "<<axis[2]<<std::endl;
vtkm::Vec<vtkm::Float32, 3> p2_p1(p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]);
vtkm::Float32 t = vtkm::Magnitude(p2_p1);
t = vtkm::Min(vtkm::Max(t, -1.0f), 1.0f);
vtkm::Float32 phi = static_cast<vtkm::Float32>(-2.0f*asin(t/(2.0f*RADIUS)));
vtkm::Float32 val = static_cast<vtkm::Float32>(sin(phi/2.0f));
axis[0] *= val;
axis[1] *= val;
axis[2] *= val;
//quaternion
vtkm::Float32 q[4] = {axis[0], axis[1], axis[2], static_cast<vtkm::Float32>(cos(phi/2.0f))};
// normalize quaternion to unit magnitude
t = 1.0f / static_cast<vtkm::Float32>(sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]));
q[0] *= t;
q[1] *= t;
q[2] *= t;
q[3] *= t;
/*
std::cout<<"P1: "<<p1[0]<<" "<<p1[1]<<" "<<p1[2]<<std::endl;
std::cout<<"P2: "<<p2[0]<<" "<<p2[1]<<" "<<p2[2]<<std::endl;
std::cout<<"T= "<<t<<std::endl;
std::cout<<"PHI= "<<phi<<std::endl;
std::cout<<"QUAT: "<<q[0]<<" "<<q[1]<<" "<<q[2]<<" "<<q[3]<<std::endl;
*/
matrix(0,0) = 1 - 2 * (q[1]*q[1] + q[2]*q[2]);
matrix(0,1) = 2 * (q[0]*q[1] + q[2]*q[3]);
matrix(0,2) = (2 * (q[2]*q[0] - q[1]*q[3]) );
matrix(1,0) = 2 * (q[0]*q[1] - q[2]*q[3]);
matrix(1,1) = 1 - 2 * (q[2]*q[2] + q[0]*q[0]);
matrix(1,2) = (2 * (q[1]*q[2] + q[0]*q[3]) );
matrix(2,0) = (2 * (q[2]*q[0] + q[1]*q[3]) );
matrix(2,1) = (2 * (q[1]*q[2] - q[0]*q[3]) );
matrix(2,2) = (1 - 2 * (q[1]*q[1] + q[0]*q[0]) );
return matrix;
}
public:
enum ViewTypeEnum { VIEW_2D, VIEW_3D };
ViewTypeEnum ViewType;
@ -423,29 +286,13 @@ public:
VTKM_CONT_EXPORT
void TrackballRotate(vtkm::Float32 x1, vtkm::Float32 y1, vtkm::Float32 x2, vtkm::Float32 y2)
{
/*
std::cout<<std::endl;
std::cout<<"*****************************************************************"<<std::endl;
std::cout<<x1<<" "<<y1<<" --> "<<x2<<" "<<y2<<std::endl;
printVec("position", view3d.Position);
printVec("lookAt", view3d.lookAt);
printVec("up", view3d.up);
std::cout<<"*****************************************************************"<<std::endl;
*/
vtkm::Matrix<vtkm::Float32,4,4> R1 = CreateTrackball(x1,y1, x2,y2);
vtkm::Matrix<vtkm::Float32,4,4> R1 = MatrixHelpers::TrackballMatrix(x1,y1, x2,y2);
//Translate matrix
vtkm::Matrix<vtkm::Float32,4,4> T1 = View::TranslateMatrix(-this->View3d.LookAt);
//vtkm::MatrixIdentity(T1);
//T1(0,3) = -view3d.lookAt[0];
//T1(1,3) = -view3d.lookAt[1];
//T1(2,3) = -view3d.lookAt[2];
vtkm::Matrix<vtkm::Float32,4,4> T1 = MatrixHelpers::TranslateMatrix(-this->View3d.LookAt);
//Translate matrix
vtkm::Matrix<vtkm::Float32,4,4> T2 = View::TranslateMatrix(this->View3d.LookAt);
//T2(0,3) = view3d.lookAt[0];
//T2(1,3) = view3d.lookAt[1];
//T2(2,3) = view3d.lookAt[2];
vtkm::Matrix<vtkm::Float32,4,4> T2 = MatrixHelpers::TranslateMatrix(this->View3d.LookAt);
vtkm::Matrix<vtkm::Float32,4,4> V1 = this->CreateViewMatrix();
V1(0,3) = 0;
@ -463,18 +310,6 @@ public:
this->View3d.Position = MultVector(MM, this->View3d.Position);
this->View3d.LookAt = MultVector(MM, this->View3d.LookAt);
this->View3d.Up = MultVector(MM, this->View3d.Up);
/*
printMtx("T1", T1);
printMtx("T2", T2);
printMtx("V1", V1);
printMtx("V2", V2);
printMtx("R1", R1);
printMtx("MM", MM);
printVec("position", this->View3d.Position);
printVec("lookAt", this->View3d.LookAt);
printVec("up", this->View3d.Up);
*/
}
};

@ -26,6 +26,7 @@
#include <vtkm/rendering/AxisAnnotation2D.h>
#include <vtkm/rendering/Color.h>
#include <vtkm/rendering/ColorBarAnnotation.h>
#include <vtkm/rendering/TextAnnotation.h>
#include <vtkm/rendering/Scene.h>
#include <vtkm/rendering/SceneRenderer.h>
#include <vtkm/rendering/View.h>
@ -98,16 +99,16 @@ class Window3D : public Window<SceneRendererType, SurfaceType,WorldAnnotatorType
{
typedef Window<SceneRendererType, SurfaceType,WorldAnnotatorType> Superclass;
public:
vtkm::rendering::Scene3D Scene;
vtkm::rendering::Scene Scene;
// 3D-specific annotations
vtkm::rendering::BoundingBoxAnnotation BoxAnnotation;
vtkm::rendering::AxisAnnotation3D XAxisAnnotation;
vtkm::rendering::AxisAnnotation3D YAxisAnnotation;
vtkm::rendering::AxisAnnotation3D ZAxisAnnotation;
ColorBarAnnotation ColorBarAnnotation;
vtkm::rendering::ColorBarAnnotation ColorBarAnnotation;
VTKM_CONT_EXPORT
Window3D(const vtkm::rendering::Scene3D &scene,
Window3D(const vtkm::rendering::Scene &scene,
const SceneRendererType &sceneRenderer,
const SurfaceType &surface,
const vtkm::rendering::View &view,
@ -138,7 +139,7 @@ public:
{
if (this->Scene.Plots.size() > 0)
{
//this->ColorBarAnnotation.SetAxisColor(eavlColor::white);
//this->ColorBarAnnotation.SetAxisColor(vtkm::rendering::Color(1,1,1));
this->ColorBarAnnotation.SetRange(this->Scene.Plots[0].ScalarRange, 5);
this->ColorBarAnnotation.SetColorTable(this->Scene.Plots[0].ColorTable);
this->ColorBarAnnotation.Render(this->View, this->WorldAnnotator, this->Surface);
@ -151,7 +152,7 @@ public:
vtkm::Bounds bounds = this->Scene.GetSpatialBounds();
vtkm::Float64 xmin = bounds.X.Min, xmax = bounds.X.Max;
vtkm::Float64 ymin = bounds.Y.Min, ymax = bounds.Y.Max;
vtkm::Float64 zmin = bounds.Z.Min, zmax = bounds.Y.Max;
vtkm::Float64 zmin = bounds.Z.Min, zmax = bounds.Z.Max;
vtkm::Float64 dx = xmax-xmin, dy = ymax-ymin, dz = zmax-zmin;
vtkm::Float64 size = vtkm::Sqrt(dx*dx + dy*dy + dz*dz);
@ -159,8 +160,16 @@ public:
this->BoxAnnotation.SetExtents(this->Scene.GetSpatialBounds());
this->BoxAnnotation.Render(this->View, this->WorldAnnotator);
///\todo: set x/y/ztest based on view
bool xtest=true, ytest=false, ztest=false;
bool xtest = this->View.View3d.LookAt[0] > this->View.View3d.Position[0];
bool ytest = this->View.View3d.LookAt[1] > this->View.View3d.Position[1];
bool ztest = this->View.View3d.LookAt[2] > this->View.View3d.Position[2];
const bool outsideedges = true; // if false, do closesttriad
if (outsideedges)
{
xtest = !xtest;
//ytest = !ytest;
}
vtkm::Float64 xrel = vtkm::Abs(dx) / size;
vtkm::Float64 yrel = vtkm::Abs(dy) / size;
@ -178,11 +187,11 @@ public:
this->XAxisAnnotation.SetRange(xmin, xmax);
this->XAxisAnnotation.SetMajorTickSize(size / 40.f, 0);
this->XAxisAnnotation.SetMinorTickSize(size / 80.f, 0);
this->XAxisAnnotation.SetLabelFontScale(size / 30.);
this->XAxisAnnotation.SetLabelFontOffset(vtkm::Float32(size / 15.f));
this->XAxisAnnotation.SetMoreOrLessTickAdjustment(xrel < .3 ? -1 : 0);
this->XAxisAnnotation.Render(this->View, this->WorldAnnotator);
this->XAxisAnnotation.Render(this->View, this->WorldAnnotator, this->Surface);
this->YAxisAnnotation.SetAxis(0);
this->YAxisAnnotation.SetAxis(1);
this->YAxisAnnotation.SetColor(Color(1,1,1));
this->YAxisAnnotation.SetTickInvert(xtest,ytest,ztest);
this->YAxisAnnotation.SetWorldPosition(xtest ? xmin : xmax,
@ -194,11 +203,11 @@ public:
this->YAxisAnnotation.SetRange(ymin, ymax);
this->YAxisAnnotation.SetMajorTickSize(size / 40.f, 0);
this->YAxisAnnotation.SetMinorTickSize(size / 80.f, 0);
this->YAxisAnnotation.SetLabelFontScale(size / 30.);
this->YAxisAnnotation.SetLabelFontOffset(vtkm::Float32(size / 15.f));
this->YAxisAnnotation.SetMoreOrLessTickAdjustment(yrel < .3 ? -1 : 0);
this->YAxisAnnotation.Render(this->View, this->WorldAnnotator);
this->YAxisAnnotation.Render(this->View, this->WorldAnnotator, this->Surface);
this->ZAxisAnnotation.SetAxis(0);
this->ZAxisAnnotation.SetAxis(2);
this->ZAxisAnnotation.SetColor(Color(1,1,1));
this->ZAxisAnnotation.SetTickInvert(xtest,ytest,ztest);
this->ZAxisAnnotation.SetWorldPosition(xtest ? xmin : xmax,
@ -210,9 +219,9 @@ public:
this->ZAxisAnnotation.SetRange(zmin, zmax);
this->ZAxisAnnotation.SetMajorTickSize(size / 40.f, 0);
this->ZAxisAnnotation.SetMinorTickSize(size / 80.f, 0);
this->ZAxisAnnotation.SetLabelFontScale(size / 30.);
this->ZAxisAnnotation.SetLabelFontOffset(vtkm::Float32(size / 15.f));
this->ZAxisAnnotation.SetMoreOrLessTickAdjustment(zrel < .3 ? -1 : 0);
this->ZAxisAnnotation.Render(this->View, this->WorldAnnotator);
this->ZAxisAnnotation.Render(this->View, this->WorldAnnotator, this->Surface);
}
};
@ -223,14 +232,14 @@ class Window2D : public Window<SceneRendererType, SurfaceType,WorldAnnotatorType
{
typedef Window<SceneRendererType, SurfaceType,WorldAnnotatorType> Superclass;
public:
vtkm::rendering::Scene2D Scene;
vtkm::rendering::Scene Scene;
// 2D-specific annotations
AxisAnnotation2D HorizontalAxisAnnotation;
AxisAnnotation2D VerticalAxisAnnotation;
ColorBarAnnotation ColorBarAnnotation;
vtkm::rendering::AxisAnnotation2D HorizontalAxisAnnotation;
vtkm::rendering::AxisAnnotation2D VerticalAxisAnnotation;
vtkm::rendering::ColorBarAnnotation ColorBarAnnotation;
VTKM_CONT_EXPORT
Window2D(const vtkm::rendering::Scene2D &scene,
Window2D(const vtkm::rendering::Scene &scene,
const SceneRendererType &sceneRenderer,
const SurfaceType &surface,
const vtkm::rendering::View &view,
@ -274,8 +283,8 @@ public:
this->View.View2d.Right);
this->HorizontalAxisAnnotation.SetMajorTickSize(0, .05, 1.0);
this->HorizontalAxisAnnotation.SetMinorTickSize(0, .02, 1.0);
//this->HorizontalAxisAnnotation.SetLabelAlignment(eavlTextAnnotation::HCenter,
// eavlTextAnnotation::Top);
this->HorizontalAxisAnnotation.SetLabelAlignment(TextAnnotation::HCenter,
TextAnnotation::Top);
this->HorizontalAxisAnnotation.Render(
this->View, this->WorldAnnotator, this->Surface);
@ -289,16 +298,16 @@ public:
this->View.View2d.Top);
this->VerticalAxisAnnotation.SetMajorTickSize(.05 / windowaspect, 0, 1.0);
this->VerticalAxisAnnotation.SetMinorTickSize(.02 / windowaspect, 0, 1.0);
//this->VerticalAxisAnnotation.SetLabelAlignment(eavlTextAnnotation::Right,
// eavlTextAnnotation::VCenter);
this->VerticalAxisAnnotation.SetLabelAlignment(TextAnnotation::Right,
TextAnnotation::VCenter);
this->VerticalAxisAnnotation.Render(
this->View, this->WorldAnnotator, this->Surface);
if (this->Scene.Plots.size() > 0)
{
//this->ColorBarAnnotation.SetAxisColor(eavlColor::white);
this->ColorBarAnnotation.SetRange(this->Scene.Plots[0].ScalarRange[0],
this->Scene.Plots[0].ScalarRange[1],
//this->ColorBarAnnotation.SetAxisColor(vtkm::rendering::Color(1,1,1));
this->ColorBarAnnotation.SetRange(this->Scene.Plots[0].ScalarRange.Min,
this->Scene.Plots[0].ScalarRange.Max,
5);
this->ColorBarAnnotation.SetColorTable(this->Scene.Plots[0].ColorTable);
this->ColorBarAnnotation.Render(

@ -37,6 +37,13 @@ public:
vtkm::Float32,
const vtkm::rendering::Color &,
bool=false) {}
virtual void AddText(vtkm::Float32, vtkm::Float32, vtkm::Float32,
vtkm::Float32, vtkm::Float32, vtkm::Float32,
vtkm::Float32, vtkm::Float32, vtkm::Float32,
vtkm::Float32,
vtkm::Float32, vtkm::Float32,
Color,
std::string) {}
};
}} //namespace vtkm::rendering

@ -20,12 +20,17 @@
#ifndef vtk_m_rendering_WorldAnnotatorGL_h
#define vtk_m_rendering_WorldAnnotatorGL_h
#include <vtkm/Matrix.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/rendering/Color.h>
#include <vtkm/rendering/Scene.h>
#include <vtkm/rendering/SceneRenderer.h>
#include <vtkm/rendering/View.h>
#include <vtkm/rendering/WorldAnnotator.h>
#include <vtkm/rendering/BitmapFont.h>
#include <vtkm/rendering/BitmapFontFactory.h>
#include <vtkm/rendering/TextureGL.h>
#include <vtkm/rendering/MatrixHelpers.h>
#include <vtkm/rendering/internal/OpenGLHeaders.h>
@ -60,6 +65,107 @@ public:
glDepthRange(0,1);
}
virtual void AddText(vtkm::Float32 ox, vtkm::Float32 oy, vtkm::Float32 oz,
vtkm::Float32 rx, vtkm::Float32 ry, vtkm::Float32 rz,
vtkm::Float32 ux, vtkm::Float32 uy, vtkm::Float32 uz,
vtkm::Float32 scale,
vtkm::Float32 anchorx, vtkm::Float32 anchory,
Color color,
std::string text)
{
vtkm::Vec<vtkm::Float32,3> o(ox,oy,oz);
vtkm::Vec<vtkm::Float32,3> r(rx,ry,rz);
vtkm::Vec<vtkm::Float32,3> u(ux,uy,uz);
vtkm::Vec<vtkm::Float32,3> n = vtkm::Cross(r,u);
vtkm::Normalize(n);
vtkm::Matrix<vtkm::Float32,4,4> m;
m = MatrixHelpers::WorldMatrix(o, r, u, n);
vtkm::Float32 ogl[16];
MatrixHelpers::CreateOGLMatrix(m, ogl);
glPushMatrix();
glMultMatrixf(ogl);
glColor3fv(color.Components);
RenderText(scale, anchorx, anchory, text);
glPopMatrix();
}
private:
BitmapFont Font;
TextureGL FontTexture;
void RenderText(vtkm::Float32 scale,
vtkm::Float32 anchorx, vtkm::Float32 anchory,
std::string text)
{
if (this->FontTexture.ID == 0)
{
Font = BitmapFontFactory::CreateLiberation2Sans();
std::vector<unsigned char> &rawpngdata = this->Font.GetRawImageData();
std::vector<unsigned char> rgba;
unsigned long width, height;
int error = decodePNG(rgba, width, height,
&rawpngdata[0], rawpngdata.size());
if (error != 0)
{
return;
}
this->FontTexture.CreateAlphaFromRGBA(int(width),int(height),rgba);
}
this->FontTexture.Enable();
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDisable(GL_LIGHTING);
//glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -.5);
glBegin(GL_QUADS);
vtkm::Float32 textwidth = this->Font.GetTextWidth(text);
vtkm::Float32 fx = -(.5f + .5f*anchorx) * textwidth;
vtkm::Float32 fy = -(.5f + .5f*anchory);
vtkm::Float32 fz = 0;
for (unsigned int i=0; i<text.length(); ++i)
{
char c = text[i];
char nextchar = (i < text.length()-1) ? text[i+1] : 0;
vtkm::Float32 vl,vr,vt,vb;
vtkm::Float32 tl,tr,tt,tb;
this->Font.GetCharPolygon(c, fx, fy,
vl, vr, vt, vb,
tl, tr, tt, tb, nextchar);
glTexCoord2f(tl, 1.f-tt);
glVertex3f(scale*vl, scale*vt, fz);
glTexCoord2f(tl, 1.f-tb);
glVertex3f(scale*vl, scale*vb, fz);
glTexCoord2f(tr, 1.f-tb);
glVertex3f(scale*vr, scale*vb, fz);
glTexCoord2f(tr, 1.f-tt);
glVertex3f(scale*vr, scale*vt, fz);
}
glEnd();
this->FontTexture.Disable();
//glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0);
glDepthMask(GL_TRUE);
glDisable(GL_ALPHA_TEST);
}
};
}} //namespace vtkm::rendering

@ -17,6 +17,7 @@
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/Bounds.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/rendering/Window.h>
#include <vtkm/rendering/RenderSurfaceOSMesa.h>
@ -33,13 +34,12 @@ void Set3DView(vtkm::rendering::View &view,
const vtkm::cont::CoordinateSystem &coords,
vtkm::Int32 w, vtkm::Int32 h)
{
vtkm::Float64 coordsBounds[6]; // Xmin,Xmax,Ymin..
coords.GetBounds(coordsBounds,VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
vtkm::Bounds coordsBounds = coords.GetBounds(VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
//set up a default view
vtkm::Vec<vtkm::Float32,3> totalExtent;
totalExtent[0] = vtkm::Float32(coordsBounds[1] - coordsBounds[0]);
totalExtent[1] = vtkm::Float32(coordsBounds[3] - coordsBounds[2]);
totalExtent[2] = vtkm::Float32(coordsBounds[5] - coordsBounds[4]);
totalExtent[0] = vtkm::Float32(coordsBounds.X.Max - coordsBounds.X.Min);
totalExtent[1] = vtkm::Float32(coordsBounds.Y.Max - coordsBounds.Y.Min);
totalExtent[2] = vtkm::Float32(coordsBounds.Z.Max - coordsBounds.Z.Min);
vtkm::Float32 mag = vtkm::Magnitude(totalExtent);
vtkm::Normalize(totalExtent);
@ -65,22 +65,14 @@ void Set2DView(vtkm::rendering::View &view,
const vtkm::cont::CoordinateSystem &coords,
vtkm::Int32 w, vtkm::Int32 h)
{
vtkm::Float64 coordsBounds[6]; // Xmin,Xmax,Ymin..
coords.GetBounds(coordsBounds,VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
vtkm::Bounds coordsBounds = coords.GetBounds(VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
//set up a default view
// totalExtent does not seem to be used
// vtkm::Vec<vtkm::Float32,3> totalExtent;
// totalExtent[0] = vtkm::Float32(coordsBounds[1] - coordsBounds[0]);
// totalExtent[1] = vtkm::Float32(coordsBounds[3] - coordsBounds[2]);
// totalExtent[2] = vtkm::Float32(coordsBounds[5] - coordsBounds[4]);
// vtkm::Float32 mag = vtkm::Magnitude(totalExtent);
// vtkm::Normalize(totalExtent);
view = vtkm::rendering::View(vtkm::rendering::View::VIEW_2D);
view.View2d.Left = static_cast<vtkm::Float32>(coordsBounds[0]);
view.View2d.Right = static_cast<vtkm::Float32>(coordsBounds[1]);
view.View2d.Bottom = static_cast<vtkm::Float32>(coordsBounds[2]);
view.View2d.Top = static_cast<vtkm::Float32>(coordsBounds[3]);
view.View2d.Left = static_cast<vtkm::Float32>(coordsBounds.X.Min);
view.View2d.Right = static_cast<vtkm::Float32>(coordsBounds.X.Max);
view.View2d.Bottom = static_cast<vtkm::Float32>(coordsBounds.Y.Min);
view.View2d.Top = static_cast<vtkm::Float32>(coordsBounds.Y.Max);
view.NearPlane = 1.f;
view.FarPlane = 100.f;
view.Width = w;
@ -112,7 +104,7 @@ void Render3D(const vtkm::cont::DataSet &ds,
vtkm::rendering::View view;
Set3DView(view, coords, W, H);
vtkm::rendering::Scene3D scene;
vtkm::rendering::Scene scene;
vtkm::rendering::Color bg(0.2f, 0.2f, 0.2f, 1.0f);
vtkm::rendering::RenderSurfaceOSMesa surface(W,H,bg);
@ -144,7 +136,7 @@ void Render2D(const vtkm::cont::DataSet &ds,
vtkm::rendering::View view;
Set2DView(view, coords, W, H);
vtkm::rendering::Scene2D scene;
vtkm::rendering::Scene scene;
vtkm::rendering::Color bg(0.2f, 0.2f, 0.2f, 1.0f);
vtkm::rendering::RenderSurfaceOSMesa surface(W,H,bg);

@ -72,7 +72,7 @@ void Render(const vtkm::cont::DataSet &ds,
vtkm::rendering::View view;
Set3DView(view, coords, W, H);
vtkm::rendering::Scene3D scene;
vtkm::rendering::Scene scene;
vtkm::rendering::Color bg(0.2f, 0.2f, 0.2f, 1.0f);
vtkm::rendering::RenderSurfaceRayTracer surface(W,H,bg);
scene.Plots.push_back(vtkm::rendering::Plot(ds.GetCellSet(),

@ -77,7 +77,7 @@ void Render(const vtkm::cont::DataSet &ds,
colorTable.AddAlphaControlPoint(0.0f, .01f);
colorTable.AddAlphaControlPoint(1.0f, .01f);
vtkm::rendering::Scene3D scene;
vtkm::rendering::Scene scene;
vtkm::rendering::Color bg(0.2f, 0.2f, 0.2f, 1.0f);
vtkm::rendering::RenderSurfaceRayTracer surface(W,H,bg);
scene.Plots.push_back(vtkm::rendering::Plot(ds.GetCellSet(),