Browse Source

attractor techdemo realtime shit

master
Joshua Moerman 13 years ago
commit
ab5a50bb97
  1. 171
      App.h
  2. 58
      GlutTest.cbp
  3. 110
      fbo.h
  4. 88
      main.cpp
  5. 32
      pngwriter/Makefile
  6. 4328
      pngwriter/pngwriter.cc
  7. 747
      pngwriter/pngwriter.h
  8. 16
      resources/attractor_2011-04-28_10-05-11-1.stf
  9. 16
      resources/attractor_2011-04-28_10-30-35-2.stf
  10. 16
      resources/attractor_2011-04-29_04-34-41-9.stf
  11. 16
      resources/attractor_2011-04-29_15-19-03-9.stf
  12. 5
      resources/myClearShader.frag
  13. 4
      resources/myClearShader.vert
  14. 9
      resources/myTeaShader.frag
  15. 7
      resources/myTeaShader.vert
  16. 145
      shader.h
  17. 11
      stfu/ExampleProgramOutput.stf
  18. 28
      stfu/LICENSE.txt
  19. 45
      stfu/STFU.cbp
  20. 21
      stfu/STFU.depend
  21. 26
      stfu/STF_Format_Example.stf
  22. 6
      stfu/arrays.stf
  23. 282
      stfu/main.cpp
  24. 4
      stfu/screenoptions.stf
  25. 107
      stfu/simple documentation.html
  26. 9
      stfu/soundoptions.stf
  27. 272
      stfu/stf.cpp
  28. 358
      stfu/stf.hpp
  29. 4
      stfu/test.stf

171
App.h

@ -0,0 +1,171 @@
#ifndef APP_H
#define APP_H
#include <algorithm>
#include <iterator>
#include <iostream>
#include <fstream>
#include <cmath>
#include <array>
#include <ratio>
#include "stfu/stf.hpp"
#include "pngwriter/pngwriter.h"
#include "shader.h"
#include "fbo.h"
static const std::string filenames[] = {
"resources/attractor_2011-04-28_10-30-35-2.stf",
"resources/attractor_2011-04-28_10-05-11-1.stf",
"resources/attractor_2011-04-29_04-34-41-9.stf",
"resources/attractor_2011-04-29_15-19-03-9.stf" };
class App {
int counter;
unsigned int width, height;
shader mshader;
shader clear_shader;
fbo mfbo;
static constexpr size_t number_of_lines = 6*50000;
static constexpr size_t number_of_vertices = 2*number_of_lines;
std::array<GLfloat, 3*number_of_vertices> lines;
std::array<GLfloat, 7> parameters;
std::array<GLfloat, 7> random_parameters;
public:
App(unsigned int w, unsigned int h) :
counter(0),
width(w),
height(h),
mshader("resources/myTeaShader.vert", "resources/myTeaShader.frag"),
clear_shader("resources/myClearShader.vert", "resources/myClearShader.frag"),
mfbo(width, height) {
set_points();
//glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glPointSize(1.0);
std::string filename = filenames[3];
set_parameters(filename);
}
~App() {
}
void resize(int w, int h) {
}
void update() {
++counter;
iterate();
if(counter % 500 == 0) {
set_parameters(filenames[rand() % 4]);
set_points();
}
}
void draw() {
clear_shader.begin();
clear_shader.set_uniform("fade", .5f);
if( counter < 5 )
clear_shader.set_uniform("fade", 1.0f);
fade();
mshader.begin();
mshader.set_uniform("steps", counter);
glRotatef(0.5, std::sin(counter/1337.0), 1.0, 0.0);
scene();
}
void fade() {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
static const GLfloat quad[] = {
1.0, 1.0,
1.0, -1.0,
-1.0, -1.0,
-1.0, 1.0 };
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, &quad[0]);
// draw a cube
glDrawArrays(GL_QUADS, 0, 4);
// deactivate vertex arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY);
}
void scene() {
glBlendFunc(GL_ONE, GL_ONE);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &lines[0]);
// draw a cube
glDrawArrays(GL_POINTS, 0, number_of_vertices);
// deactivate vertex arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY);
//save_screen();
}
void iterate() {
for(size_t i = 0; i < number_of_lines; ++i) {
GLfloat* vectorNew = &lines[3*2*i];
GLfloat* vectorOld = &lines[3*2*i+3];
if(counter % 2) std::swap(vectorNew, vectorOld);
vectorNew[0] = parameters[0]*(vectorOld[2] + parameters[1]);
vectorNew[1] = parameters[2]*(vectorOld[0] + parameters[3]);
vectorNew[2] = parameters[4]*(vectorOld[1] + parameters[5]);
const double dist = vectorNew[0]*vectorNew[0] + vectorNew[1]*vectorNew[1] + vectorNew[2]*vectorNew[2];
if(dist > parameters[6]*parameters[6]) {
const double sqrtDist = std::sqrt(dist);
const double p = 1.0 - parameters[6] * (static_cast<int>(sqrtDist / parameters[6]) + 1.0) / sqrtDist;
vectorNew[0] *= p;
vectorNew[1] *= p;
vectorNew[2] *= p;
}
}
for(size_t i = 0; i < 7; ++i){
parameters[i] += random_parameters[i];
}
}
void save_screen(){
unsigned char data[width*height*6];
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_SHORT, data);
char filename[256];
sprintf(filename, "render/shot_%08d.png", counter);
pngwriter png(width, height, &data[0], filename);
png.close();
}
void set_parameters(std::string filename){
stfu::node file;
file.read(filename.c_str());
for(unsigned int i = 0; i < 7; ++i) {
stfu::node const attractorParameters = file.getChild("AttractorKernel").getChild("parameters");
parameters[i] = atof(attractorParameters.getValue(i).c_str());
random_parameters[i] = (rand() / (double)RAND_MAX - 0.5) * counter / 500000.0;
}
}
void set_points(){
std::generate(lines.begin(), lines.end(), []() { return 2.0 * rand() / (double)RAND_MAX - 1.0; });
}
};
#endif // APP_H

58
GlutTest.cbp

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="GlutTest" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
<Option output="bin/Debug/GlutTest" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release">
<Option output="bin/Release/GlutTest" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
<Add option="-DNDEBUG" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add option="-fexceptions" />
</Compiler>
<Linker>
<Add library="GLEW" />
<Add library="glut" />
<Add library="png" />
</Linker>
<Unit filename="App.h" />
<Unit filename="fbo.h" />
<Unit filename="main.cpp" />
<Unit filename="pngwriter/pngwriter.cc" />
<Unit filename="pngwriter/pngwriter.h" />
<Unit filename="resources/myClearShader.frag" />
<Unit filename="resources/myClearShader.vert" />
<Unit filename="resources/myTeaShader.frag" />
<Unit filename="resources/myTeaShader.vert" />
<Unit filename="shader.h" />
<Unit filename="stfu/stf.cpp" />
<Unit filename="stfu/stf.hpp" />
<Extensions>
<code_completion />
<debugger />
</Extensions>
</Project>
</CodeBlocks_project_file>

110
fbo.h

@ -0,0 +1,110 @@
#ifndef FBO_H
#define FBO_H
#include <stdexcept>
#include <GL/glew.h>
#include <GL/freeglut.h>
class fbo {
int width, height;
GLuint fbo_number;
std::map<GLenum, GLuint> renderbuffers;
GLuint texture_id;
public:
fbo(int width, int height) : width(width), height(height) {
check_status();
glGenBuffers(1, &fbo_number);
begin();
// generate texture
glGenTextures(1, &texture_id);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_BYTE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0);
// attach depth
create_attach_renderbuffer(GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT);
// attach stencil
create_attach_renderbuffer(GL_STENCIL_INDEX, GL_STENCIL_ATTACHMENT);
check_status();
}
~fbo() {
end();
glDeleteFramebuffers(1, &fbo_number);
for(auto& it : renderbuffers){
glDeleteFramebuffers(1, &it.second);
}
glDeleteTextures(1, &texture_id);
}
void begin(){
glBindFramebuffer(GL_FRAMEBUFFER, fbo_number);
}
void end(){
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
private:
void create_attach_renderbuffer(GLenum format, GLenum attachment_point) {
GLuint buffer;
glGenRenderbuffers(1, &buffer);
glBindRenderbuffer(GL_RENDERBUFFER, buffer);
glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment_point, GL_RENDERBUFFER, buffer);
renderbuffers[format] = buffer;
}
void check_status() {
GLenum status = glGetError();
if(status != GL_NO_ERROR) {
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE:
std::cout << "FRAMEBUFFER_COMPLETE - OK" << std::endl;
return;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
std::cout << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT" << std::endl;
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
std::cout << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT" << std::endl;
break;
/*case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
std::cout << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS" << std::endl;
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
std::cout << "FRAMEBUFFER_INCOMPLETE_FORMATS" << std::endl;
break;*/
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
std::cout << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER" << std::endl;
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
std::cout << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER" << std::endl;
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
std::cout << "FRAMEBUFFER_UNSUPPORTED" << std::endl;
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
std::cout << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE" << std::endl;
break;
default:
std::cout << "UNKNOWN FRAMEBUFFER ERROR" << std::endl;
break;
}
throw std::runtime_error("I will not continu..");
}
}
};
#endif // FBO_H

88
main.cpp

@ -0,0 +1,88 @@
#include <iostream>
#include <stdexcept>
#include <chrono>
#include <thread>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include "App.h"
#define kWindowWidth 1280
#define kWindowHeight 700
App* app_ptr = 0;
unsigned int const frames_per_second = 100.0;
typedef std::chrono::high_resolution_clock clock_type;
size_t frame_count = 0;
clock_type::time_point begin_time;
void begin() {
app_ptr = new App(kWindowWidth, kWindowHeight);
begin_time = clock_type::now();
}
void end() {
auto end = clock_type::now();
auto difference = end-begin_time;
auto time_elapsed = difference.count()*clock_type::duration::period::num/(double)clock_type::duration::period::den;
std::cout << "Did " << frame_count << " frames in " << time_elapsed << " seconds." << std::endl;
std::cout << "That's " << frame_count/time_elapsed << " frames per second." << std::endl;
delete app_ptr;
}
int main(int argc, char** argv) {
// let glut create a window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_ALPHA);
glutInitWindowSize(kWindowWidth, kWindowHeight);
glutCreateWindow("OpenGL");
// we need glew for shaders
auto err = glewInit();
if(err != GLEW_OK) {
throw std::runtime_error("A glew error");
}
// all callbacks (c++0x lambdas woei)
glutDisplayFunc([] {
auto const time_step = std::chrono::milliseconds(1000/frames_per_second);
static auto previous_timepoint = clock_type::now();
auto const current_timepoint = clock_type::now();
auto const difference = current_timepoint - previous_timepoint;
if(difference > time_step) {
app_ptr->update();
app_ptr->draw();
glutSwapBuffers();
//glFlush();
++frame_count;
previous_timepoint = current_timepoint-(difference%time_step);
} else {
usleep((time_step-difference).count()*1000000*clock_type::duration::period::num/(double)clock_type::duration::period::den/2);
//std::sleep_for((time_step-difference)/2);
}
glutPostRedisplay();
});
glutReshapeFunc([](int w, int h) {app_ptr->resize(w, h);});
glutCloseFunc(end); // freeglut extension
// my app-object
begin();
// GO!
glutMainLoop();
return 0;
}

32
pngwriter/Makefile

@ -0,0 +1,32 @@
############ PARTIAL MAKEFILE FOR PNGWRITER ######################################
#
# Website: Main: http://pngwriter.sourceforge.net/
# Author: Paul Blackburn
# Email: individual61@users.sourceforge.net
# Version: 0.5.4 (19 / II / 2009)
# License: GNU General Public License
# Copyright 2002, 2003, 2004, 2005, 2006, 2007,
# 2008, 2009 Paul Blackburn
#
##################################################################################
include ../make.include
OBJECTS=pngwriter.o
all: libpngwriter.a
libpngwriter.a: $(OBJECTS)
ar rv $@ $^
ranlib $@
pngwriter.o: pngwriter.cc pngwriter.h
$(CXX) $(CXXFLAGS) $(INC) -g -c -o pngwriter.o pngwriter.cc
clean :
rm -f $(OBJECTS) libpngwriter.a pngtest.cc~ pngwriter.cc~
rm -f pngwriter.h~ Makefile~
rm -f .DS_Store

4328
pngwriter/pngwriter.cc

File diff suppressed because it is too large

747
pngwriter/pngwriter.h

@ -0,0 +1,747 @@
//********** pngwriter.h **********************************************
// Author: Paul Blackburn
//
// Email: individual61@users.sourceforge.net
//
// Version: 0.5.4 (19 / II / 2009)
//
// Description: Library that allows plotting a 48 bit
// PNG image pixel by pixel, which can
// then be opened with a graphics program.
//
// License: GNU General Public License
// Copyright 2002, 2003, 2004, 2005, 2006, 2007,
// 2008, 2009 Paul Blackburn
//
// Website: Main: http://pngwriter.sourceforge.net/
// Sourceforge.net: http://sourceforge.net/projects/pngwriter/
// Freshmeat.net: http://freshmeat.net/projects/pngwriter/
//
// Documentation: This header file is commented, but for a
// quick reference document, and support,
// take a look at the website.
//
//*************************************************************************
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* */
#ifndef PNGWRITER_H
#define PNGWRITER_H 1
#define PNGWRITER_VERSION 0.54
#define NO_FREETYPE
#include <png.h>
// REMEMBER TO ADD -DNO_FREETYPE TO YOUR COMPILATION FLAGS IF PNGwriter WAS
// COMPILED WITHOUT FREETYPE SUPPORT!!!
//
// RECUERDA AGREGAR -DNO_FREETYPE A TUS OPCIONES DE COMPILACION SI PNGwriter
// FUE COMPILADO SIN SOPORTE PARA FREETYPE!!!
//
#ifndef NO_FREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
#endif
#ifdef OLD_CPP // For compatibility with older compilers.
#include <iostream.h>
#include <math.h>
#include <wchar.h>
#include <string.h>
using namespace std;
#endif // from ifdef OLD_CPP
#ifndef OLD_CPP // Default situation.
#include <iostream>
#include <cmath>
#include <cwchar>
#include <string>
#endif // from ifndef OLD_CPP
//png.h must be included before FreeType headers.
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>
#define PNG_BYTES_TO_CHECK (4)
#define PNGWRITER_DEFAULT_COMPRESSION (6)
class pngwriter {
private:
char* filename_;
char* textauthor_;
char* textdescription_;
char* texttitle_;
char* textsoftware_;
bool should_free;
int height_;
int width_;
int backgroundcolour_;
int bit_depth_;
int rowbytes_;
int colortype_;
int compressionlevel_;
bool transformation_; // Required by Mikkel's patch
unsigned char * * graph_;
double filegamma_;
double screengamma_;
void circle_aux(int xcentre, int ycentre, int x, int y, int red, int green, int blue);
void circle_aux_blend(int xcentre, int ycentre, int x, int y, double opacity, int red, int green, int blue);
int check_if_png(char* file_name, FILE** fp);
int read_png_info(FILE* fp, png_structp* png_ptr, png_infop* info_ptr);
int read_png_image(FILE* fp, png_structp png_ptr, png_infop info_ptr,
png_bytepp* image, png_uint_32* width, png_uint_32* height);
void flood_fill_internal(int xstart, int ystart, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue);
void flood_fill_internal_blend(int xstart, int ystart, double opacity, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue);
#ifndef NO_FREETYPE
void my_draw_bitmap(FT_Bitmap* bitmap, int x, int y, double red, double green, double blue);
void my_draw_bitmap_blend(FT_Bitmap* bitmap, int x, int y,double opacity, double red, double green, double blue);
#endif
/* The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/
* which is a page that belongs to Nan C. Schaller, though
* these algorithms appear to be the work of Eugene Vishnevsky.
* */
void HSVtoRGB(double* r, double* g, double* b, double h, double s, double v);
void RGBtoHSV(float r, float g, float b, float* h, float* s, float* v);
/* drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
* ( <gurkan@linuks.mine.nu>, http://www.linuks.mine.nu/ )
* */
void drawtop(long x1,long y1,long x2,long y2,long x3, int red, int green, int blue);
void drawbottom(long x1,long y1,long x2,long x3,long y3, int red, int green, int blue);
void drawbottom_blend(long x1,long y1,long x2,long x3,long y3, double opacity, int red, int green, int blue);
void drawtop_blend(long x1,long y1,long x2,long y2,long x3, double opacity, int red, int green, int blue);
public:
/* General Notes
* It is important to remember that all functions that accept an argument of type "const char *" will also
* accept "char *", this is done so you can have a changing filename (to make many PNG images in series
* with a different name, for example), and to allow you to use string type objects which can be easily
* turned into const char * (if theString is an object of type string, then it can be used as a const char *
* by saying theString.c_str()).
* It is also important to remember that whenever a function has a colour coeffiecient as its argument,
* that argument can be either an int from 0 to 65535 or a double from 0.0 to 1.0.
* It is important to make sure that you are calling the function with the type that you want.
* Remember that 1 is an int, while 1.0 is a double, and will thus determine what version of the function
* will be used. Similarly, do not make the mistake of calling for example plot(x, y, 0.0, 0.0, 65535),
* because
* there is no plot(int, int, double, double, int).
* Also, please note that plot() and read() (and the functions that use them internally)
* are protected against entering, for example, a colour coefficient that is over 65535
* or over 1.0. Similarly, they are protected against negative coefficients. read() will return 0
* when called outside the image range. This is actually useful as zero-padding should you need it.
* */
/* Compilation
* A typical compilation would look like this:
*
* g++ my_program.cc -o my_program freetype-config --cflags \
* -I/usr/local/include -L/usr/local/lib -lpng -lpngwriter -lz -lfreetype
*
* If you did not compile PNGwriter with FreeType support, then remove the
* FreeType-related flags and add -DNO_FREETYPE above.
* */
/* Constructor
* The constructor requires the width and the height of the image, the background colour for the
* image and the filename of the file (a pointer or simple "myfile.png"). The background colour
* can only be initialized to a shade of grey (once the object has been created you can do whatever
* you want, though), because generally one wants either a white (65535 or 1.0) or a black (0 or 0.0)
* background to start with.
* The default constructor creates a PNGwriter instance that is 250x250, white background,
* and filename "out.png".
* Tip: The filename can be given as easily as:
* pngwriter mypng(300, 300, 0.0, "myfile.png");
* Tip: If you are going to create a PNGwriter instance for reading in a file that already exists,
* then width and height can be 1 pixel, and the size will be automatically adjusted once you use
* readfromfile().
* */
pngwriter();
pngwriter(const pngwriter& rhs);
pngwriter(int width, int height, int backgroundcolour, char* filename);
pngwriter(int width, int height, double backgroundcolour, char* filename);
pngwriter(int width, int height, int backgroundcolour, const char* filename);
pngwriter(int width, int height, unsigned char * data, const char* filename);
pngwriter(int width, int height, double backgroundcolour, const char* filename);
/* Destructor
* */
~pngwriter();
/* Assignment Operator
* */
pngwriter& operator = (const pngwriter& rhs);
/* Plot
* With this function a pixel at coordinates (x, y) can be set to the desired colour.
* The pixels are numbered starting from (1, 1) and go to (width, height).
* As with most functions in PNGwriter, it has been overloaded to accept either int arguments
* for the colour coefficients, or those of type double. If they are of type int,
* they go from 0 to 65535. If they are of type double, they go from 0.0 to 1.0.
* Tip: To plot using red, then specify plot(x, y, 1.0, 0.0, 0.0). To make pink,
* just add a constant value to all three coefficients, like this:
* plot(x, y, 1.0, 0.4, 0.4).
* Tip: If nothing is being plotted to your PNG file, make sure that you remember
* to close() the instance before your program is finished, and that the x and y position
* is actually within the bounds of your image. If either is not, then PNGwriter will
* not complain-- it is up to you to check for this!
* Tip: If you try to plot with a colour coefficient out of range, a maximum or minimum
* coefficient will be assumed, according to the given coefficient. For example, attempting
* to plot plot(x, y, 1.0,-0.2,3.7) will set the green coefficient to 0 and the red coefficient
* to 1.0.
* */
void plot(int x, int y, int red, int green, int blue);
void plot(int x, int y, double red, double green, double blue);
/* Plot HSV
* With this function a pixel at coordinates (x, y) can be set to the desired colour,
* but with the colour coefficients given in the Hue, Saturation, Value colourspace.
* This has the advantage that one can determine the colour that will be plotted with
* only one parameter, the Hue. The colour coefficients must go from 0 to 65535 and
* be of type int, or be of type double and go from 0.0 to 1.0.
* */
void plotHSV(int x, int y, double hue, double saturation, double value);
void plotHSV(int x, int y, int hue, int saturation, int value);
/* Read
* With this function we find out what colour the pixel (x, y) is. If "colour" is 1,
* it will return the red coefficient, if it is set to 2, the green one, and if
* it set to 3, the blue colour coefficient will be returned,
* and this returned value will be of type int and be between 0 and 65535.
* Note that if you call read() on a pixel outside the image range, the value returned
* will be 0.
* */
int read(int x, int y, int colour);
/* Read, Average
* Same as the above, only that the average of the three colour coefficients is returned.
*/
int read(int x, int y);
/* dRead
* With this function we find out what colour the pixel (x, y) is. If "colour" is 1,
* it will return the red coefficient, if it is set to 2, the green one, and if
* it set to 3, the blue colour coefficient will be returned,
* and this returned value will be of type double and be between 0.0 and 1.0.
* Note that if you call dread() outside the image range, the value returned will be 0.0
* */
double dread(int x, int y, int colour);
/* dRead, Average
* Same as the above, only that the average of the three colour coefficients is returned.
*/
double dread(int x, int y);
/* Read HSV
* With this function we find out what colour the pixel (x, y) is, but in the Hue,
* Saturation, Value colourspace. If "colour" is 1,
* it will return the Hue coefficient, if it is set to 2, the Saturation one, and if
* it set to 3, the Value colour coefficient will be returned, and this returned
* value will be of type int and be between 0 and 65535. Important: If you attempt
* to read the Hue of a pixel that is a shade of grey, the value returned will be
* nonsensical or even NaN. This is just the way the RGB -> HSV algorithm works:
* the Hue of grey is not defined. You might want to check whether the pixel
* you are reading is grey before attempting a readHSV().
* Tip: This is especially useful for categorizing sections of the image according
* to their colour.
* */
int readHSV(int x, int y, int colour);
/* dRead HSV
* With this function we find out what colour the pixel (x, y) is, but in the Hue,
* Saturation, Value colourspace. If "colour" is 1,
* it will return the Hue coefficient, if it is set to 2, the Saturation one, and if
* it set to 3, the Value colour coefficient will be returned,
* and this returned value will be of type double and be between 0.0 and 1.0.
* */
double dreadHSV(int x, int y, int colour);
/* Clear
* The whole image is set to black.
* */
void clear(void);
/* Close
* Close the instance of the class, and write the image to disk.
* Tip: If you do not call this function before your program ends, no image
* will be written to disk.
* */
void close(void);
/* Rename
* To rename the file once an instance of pngwriter has been created.
* Useful for assigning names to files based upon their content.
* Tip: This is as easy as calling pngwriter_rename("newname.png")
* If the argument is a long unsigned int, for example 77, the filename will be changed to
* 0000000077.png
* Tip: Use this to create sequences of images for movie generation.
* */
void pngwriter_rename(char* newname);
void pngwriter_rename(const char* newname);
void pngwriter_rename(long unsigned int index);
/* Figures
* These functions draw basic shapes. Available in both int and double versions.
* The line functions use the fast Bresenham algorithm. Despite the name,
* the square functions draw rectangles. The circle functions use a fast
* integer math algorithm. The filled circle functions make use of sqrt().
* */
void line(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue);
void line(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue);
void triangle(int x1, int y1, int x2, int y2, int x3, int y3, int red, int green, int blue);
void triangle(int x1, int y1, int x2, int y2, int x3, int y3, double red, double green, double blue);
void square(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue);
void square(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue);
void filledsquare(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue);
void filledsquare(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue);
void circle(int xcentre, int ycentre, int radius, int red, int green, int blue);
void circle(int xcentre, int ycentre, int radius, double red, double green, double blue);
void filledcircle(int xcentre, int ycentre, int radius, int red, int green, int blue);
void filledcircle(int xcentre, int ycentre, int radius, double red, double green, double blue);
/* Read From File
* Open the existing PNG image, and copy it into this instance of the class. It is important to mention
* that PNG variants are supported. Very generally speaking, most PNG files can now be read (as of version 0.5.4),
* but if they have an alpha channel it will be completely stripped. If the PNG file uses GIF-style transparency
* (where one colour is chosen to be transparent), PNGwriter will not read the image properly, but will not
* complain. Also, if any ancillary chunks are included in the PNG file (chroma, filter, etc.), it will render
* with a slightly different tonality. For the vast majority of PNGs, this should not be an issue. Note:
* If you read an 8-bit PNG, the internal representation of that instance of PNGwriter will be 8-bit (PNG
* files of less than 8 bits will be upscaled to 8 bits). To convert it to 16-bit, just loop over all pixels,
* reading them into a new instance of PNGwriter. New instances of PNGwriter are 16-bit by default.
* */
void readfromfile(char* name);
void readfromfile(const char* name);
/* Get Height
* When you open a PNG with readfromfile() you can find out its height with this function.
* */
int getheight(void);
/* Get Width
* When you open a PNG with readfromfile() you can find out its width with this function.
* */
int getwidth(void);
/* Set Compression Level
* Set the compression level that will be used for the image. -1 is to use the default,
* 0 is none, 9 is best compression.
* Remember that this will affect how long it will take to close() the image. A value of 2 or 3
* is good enough for regular use, but for storage or transmission you might want to take the time
* to set it at 9.
* */
void setcompressionlevel(int level);
/* Get Bit Depth
* When you open a PNG with readfromfile() you can find out its bit depth with this function.
* Mostly for troubleshooting uses.
* */
int getbitdepth(void);
/* Get Colour Type
* When you open a PNG with readfromfile() you can find out its colour type (libpng categorizes
* different styles of image data with this number).
* Mostly for troubleshooting uses.
* */
int getcolortype(void);
/* Set Gamma Coeff
* Set the image's gamma (file gamma) coefficient. This is experimental, but use it if your image's colours seem too bright
* or too dark. The default value of 0.5 should be fine. The standard disclaimer about Mac and PC gamma
* settings applies.
* */
void setgamma(double gamma);
/* Get Gamma Coeff
* Get the image's gamma coefficient. This is experimental.
* */
double getgamma(void);
/* Bezier Curve
* (After Frenchman Pierre BŽzier from Regie Renault)
* A collection of formulae for describing curved lines
* and surfaces, first used in 1972 to model automobile surfaces.
* (from the The Free On-line Dictionary of Computing)
* See http://www.moshplant.com/direct-or/bezier/ for one of many
* available descriptions of bezier curves.
* There are four points used to define the curve: the two endpoints
* of the curve are called the anchor points, while the other points,
* which define the actual curvature, are called handles or control points.
* Moving the handles lets you modify the shape of the curve.
* */
void bezier(int startPtX, int startPtY,
int startControlX, int startControlY,
int endPtX, int endPtY,
int endControlX, int endControlY,
double red, double green, double blue);
void bezier(int startPtX, int startPtY,
int startControlX, int startControlY,
int endPtX, int endPtY,
int endControlX, int endControlY,
int red, int green, int blue);
/* Set Text
* Sets the text information in the PNG header. If it is not called, the default is used.
*/
void settext(char* title, char* author, char* description, char* software);
void settext(const char* title, const char* author, const char* description, const char* software);
/* Version Number
* Returns the PNGwriter version number.
*/
static double version(void);
/* Write PNG
* Writes the PNG image to disk. You can still change the PNGwriter instance after this.
* Tip: This is exactly the same as close(), but easier to remember.
* Tip: To make a sequence of images using only one instance of PNGwriter, alter the image, change its name,
* write_png(), then alter the image, change its name, write_png(), etc.
*/
void write_png(void);
/* Plot Text
* Uses the Freetype2 library to set text in the image. face_path is the file path to a
* TrueType font file (.ttf) (FreeType2 can also handle other types). fontsize specifices the approximate
* height of the rendered font in pixels. x_start and y_start specify the placement of the
* lower, left corner of the text string. angle is the text angle in radians. text is the text to be rendered.
* The colour coordinates can be doubles from 0.0 to 1.0 or ints from 0 to 65535.
* Tip: PNGwriter installs a few fonts in /usr/local/share/pngwriter/fonts to get you started.
* Tip: Remember to add -DNO_FREETYPE to your compilation flags if PNGwriter was compiled without FreeType support.
* */
void plot_text(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double red, double green, double blue);
void plot_text(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, int red, int green, int blue);
/* Plot UTF-8 Text
* Same as the above, but the text to be plotted is encoded in UTF-8. Why would you want this? To be able to plot
* all characters available in a large TrueType font, for example: for rendering Japenese, Chinese and other
* languages not restricted to the standard 128 character ASCII space.
* Tip: The quickest way to get a string into UTF-8 is to write it in an adequate text editor, and save it as a file
* in UTF-8 encoding, which can then be read in in binary mode.
* */
void plot_text_utf8(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double red, double green, double blue);
void plot_text_utf8(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, int red, int green, int blue);
/* Bilinear Interpolation of Image
* Given a floating point coordinate (x from 0.0 to width, y from 0.0 to height),
* this function will return the interpolated colour intensity specified by
* colour (where red = 1, green = 2, blue = 3).
* bilinear_interpolate_read() returns an int from 0 to 65535, and
* bilinear_interpolate_dread() returns a double from 0.0 to 1.0.
* Tip: Especially useful for enlarging an image.
* */
int bilinear_interpolation_read(double x, double y, int colour);
double bilinear_interpolation_dread(double x, double y, int colour);
/* Plot Blend
* Plots the colour given by red, green blue, but blended with the existing pixel
* value at that position. opacity is a double that goes from 0.0 to 1.0.
* 0.0 will not change the pixel at all, and 1.0 will plot the given colour.
* Anything in between will be a blend of both pixel levels. Please note: This is neither
* alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels.
* */
void plot_blend(int x, int y, double opacity, int red, int green, int blue);
void plot_blend(int x, int y, double opacity, double red, double green, double blue);
/* Invert
* Inverts the image in RGB colourspace.
* */
void invert(void);
/* Resize Image
* Resizes the PNGwriter instance. Note: All image data is set to black (this is
* a resizing, not a scaling, of the image).
* */
void resize(int width, int height);
/* Boundary Fill
* All pixels adjacent to the start pixel will be filled with the fill colour, until the boundary colour is encountered.
* For example, calling boundary_fill() with the boundary colour set to red, on a pixel somewhere inside a red circle,
* will fill the entire circle with the desired fill colour. If, on the other hand, the circle is not the boundary colour,
* the rest of the image will be filled.
* The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
* */
void boundary_fill(int xstart, int ystart, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ;
void boundary_fill(int xstart, int ystart, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ;
/* Flood Fill
* All pixels adjacent to the start pixel will be filled with the fill colour, if they are the same colour as the
* start pixel. For example, calling flood_fill() somewhere in the interior of a solid blue rectangle will colour
* the entire rectangle the fill colour. The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
* */
void flood_fill(int xstart, int ystart, double fill_red, double fill_green, double fill_blue) ;
void flood_fill(int xstart, int ystart, int fill_red, int fill_green, int fill_blue) ;
/* Polygon
* This function takes an array of integer values containing the coordinates of the vertexes of a polygon.
* Note that if you want a closed polygon, you must repeat the first point's coordinates for the last point.
* It also requires the number of points contained in the array. For example, if you wish to plot a triangle,
* the array will contain 6 elements, and the number of points is 3. Be very careful about this; if you specify the wrong number
* of points, your program will either segfault or produce points at nonsensical coordinates.
* The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
* */
void polygon(int* points, int number_of_points, double red, double green, double blue);
void polygon(int* points, int number_of_points, int red, int green, int blue);
/* Plot CMYK
* Plot a point in the Cyan, Magenta, Yellow, Black colourspace. Please note that this colourspace is
* lossy, i.e. it cannot reproduce all colours on screen that RGB can. The difference, however, is
* barely noticeable. The algorithm used is a standard one. The colour components are either
* doubles from 0.0 to 1.0 or ints from 0 to 65535.
* */
void plotCMYK(int x, int y, double cyan, double magenta, double yellow, double black);
void plotCMYK(int x, int y, int cyan, int magenta, int yellow, int black);
/* Read CMYK, Double version
* Get a pixel in the Cyan, Magenta, Yellow, Black colourspace. if 'colour' is 1, the Cyan component will be returned
* as a double from 0.0 to 1.0. If 'colour is 2, the Magenta colour component will be returned, and so on, up to 4.
* */
double dreadCMYK(int x, int y, int colour);
/* Read CMYK
* Same as the above, but the colour components returned are an int from 0 to 65535.
* */
int readCMYK(int x, int y, int colour);
/* Scale Proportional
* Scale the image using bilinear interpolation. If k is greater than 1.0, the image will be enlarged.
* If k is less than 1.0, the image will be shrunk. Negative or null values of k are not allowed.
* The image will be resized and the previous content will be replaced by the scaled image.
* Tip: use getheight() and getwidth() to find out the new width and height of the scaled image.
* Note: After scaling, all images will have a bit depth of 16, even if the original image had
* a bit depth of 8.
* */
void scale_k(double k);
/* Scale Non-Proportional
* Scale the image using bilinear interpolation, with different horizontal and vertical scale factors.
* */
void scale_kxky(double kx, double ky);
/* Scale To Target Width and Height
* Scale the image in such a way as to meet the target width and height.
* Tip: if you want to keep the image proportional, scale_k() might be more appropriate.
* */
void scale_wh(int finalwidth, int finalheight);
/* Blended Functions
* All these functions are identical to their non-blended types. They take an extra argument, opacity, which is
* a double from 0.0 to 1.0 and represents how much of the original pixel value is retained when plotting the
* new pixel. In other words, if opacity is 0.7, then after plotting, the new pixel will be 30% of the
* original colour the pixel was, and 70% of the new colour, whatever that may be. As usual, each function
* is available in int or double versions. Please note: This is neither alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels.
* */
// Start Blended Functions
void plotHSV_blend(int x, int y, double opacity, double hue, double saturation, double value);
void plotHSV_blend(int x, int y, double opacity, int hue, int saturation, int value);
void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue);
void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue);
void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue);
void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue);
void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue);
void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue);
void circle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue);
void circle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue);
void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue);
void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue);
void bezier_blend(int startPtX, int startPtY,
int startControlX, int startControlY,
int endPtX, int endPtY,
int endControlX, int endControlY,
double opacity,
double red, double green, double blue);
void bezier_blend(int startPtX, int startPtY,
int startControlX, int startControlY,
int endPtX, int endPtY,
int endControlX, int endControlY,
double opacity,
int red, int green, int blue);
void plot_text_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, double red, double green, double blue);
void plot_text_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, int red, int green, int blue);
void plot_text_utf8_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, double red, double green, double blue);
void plot_text_utf8_blend(char* face_path, int fontsize, int x_start, int y_start, double angle, char* text, double opacity, int red, int green, int blue);
void boundary_fill_blend(int xstart, int ystart, double opacity, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ;
void boundary_fill_blend(int xstart, int ystart, double opacity, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ;
void flood_fill_blend(int xstart, int ystart, double opacity, double fill_red, double fill_green, double fill_blue) ;
void flood_fill_blend(int xstart, int ystart, double opacity, int fill_red, int fill_green, int fill_blue) ;
void polygon_blend(int* points, int number_of_points, double opacity, double red, double green, double blue);
void polygon_blend(int* points, int number_of_points, double opacity, int red, int green, int blue);
void plotCMYK_blend(int x, int y, double opacity, double cyan, double magenta, double yellow, double black);
void plotCMYK_blend(int x, int y, double opacity, int cyan, int magenta, int yellow, int black);
// End of Blended Functions
/* Laplacian
* This function applies a discrete laplacian to the image, multiplied by a constant factor.
* The kernel used in this case is:
* 1.0 1.0 1.0
* 1.0 -8.0 1.0
* 1.0 1.0 1.0
* Basically, this works as an edge detector. The current pixel is assigned the sum of all neighbouring
* pixels, multiplied by the corresponding kernel element. For example, imagine a pixel and its 8 neighbours:
* 1.0 1.0 0.0 0.0
* 1.0 ->1.0<- 0.0 0.0
* 1.0 1.0 0.0 0.0
* This represents a border between white and black, black is on the right. Applying the laplacian to
* the pixel specified above pixel gives:
* 1.0*1.0 + 1.0*1.0 + 0.0*1.0 +
* 1.0*1.0 + 1.0*-8.0 + 0.0*1.0 +
* 1.0*1.0 + 1.0*1.0 + 0.0*1.0 = -3.0
* Applying this to the pixel to the right of the pixel considered previously, we get a sum of 3.0.
* That is, after passing over an edge, we get a high value for the pixel adjacent to the edge. Since
* PNGwriter limits the colour components if they are off-scale, and the result of the laplacian
* may be negative, a scale factor and an offset value are included. This might be useful for
* keeping things within range or for bringing out more detail in the edge detection. The
* final pixel value will be given by:
* final value = laplacian(original pixel)*k + offset
* Tip: Try a value of 1.0 for k to start with, and then experiment with other values.
* */
void laplacian(double k, double offset);
/* Filled Triangle
* Draws the triangle specified by the three pairs of points in the colour specified
* by the colour coefficients. The colour components are either doubles from 0.0 to
* 1.0 or ints from 0 to 65535.
* */
void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, int red, int green, int blue);
void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, double red, double green, double blue);
/* Filled Triangle, Blended
* Draws the triangle specified by the three pairs of points in the colour specified
* by the colour coefficients, and blended with the background. See the description for Blended Functions.
* The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
* */
void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, int red, int green, int blue);
void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, double red, double green, double blue);
/* Arrow, Filled Arrow
* Plots an arrow from (x1, y1) to (x2, y2) with the arrowhead at the second point, given the size in pixels
* and the angle in radians of the arrowhead. The plotted arrow consists of one main line, and two smaller
* lines originating from the second point. Filled Arrow plots the same, but the arrowhead is a solid triangle.
* Tip: An angle of 10 to 30 degrees looks OK.
* */
void arrow(int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue);
void arrow(int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue);
void filledarrow(int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue);
void filledarrow(int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue);
/* Cross, Maltese Cross
* Plots a simple cross at x, y, with the specified height and width, and in the specified colour.
* Maltese cross plots a cross, as before, but adds bars at the end of each arm of the cross.
* The size of these bars is specified with x_bar_height and y_bar_width.
* The cross will look something like this:
*
* ----- <-- ( y_bar_width)
* |
* |
* |-------| <-- ( x_bar_height )
* |
* |
* -----
* */
void cross(int x, int y, int xwidth, int yheight, double red, double green, double blue);
void cross(int x, int y, int xwidth, int yheight, int red, int green, int blue);
void maltesecross(int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, double red, double green, double blue);
void maltesecross(int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, int red, int green, int blue);
/* Diamond and filled diamond
* Plots a diamond shape, given the x, y position, the width and height, and the colour.
* Filled diamond plots a filled diamond.
* */
void filleddiamond(int x, int y, int width, int height, int red, int green, int blue);
void diamond(int x, int y, int width, int height, int red, int green, int blue);
void filleddiamond(int x, int y, int width, int height, double red, double green, double blue);
void diamond(int x, int y, int width, int height, double red, double green, double blue);
/* Get Text Width, Get Text Width UTF8
* Returns the approximate width, in pixels, of the specified *unrotated* text. It is calculated by adding
* each letter's width and kerning value (as specified in the TTF file). Note that this will not
* give the position of the farthest pixel, but it will give a pretty good idea of what area the
* text will occupy. Tip: The text, when plotted unrotated, will fit approximately in a box with its lower left corner at
* (x_start, y_start) and upper right at (x_start + width, y_start + size), where width is given by get_text_width()
* and size is the specified size of the text to be plotted. Tip: Text plotted at position
* (x_start, y_start), rotated with a given 'angle', and of a given 'size'
* whose width is 'width', will fit approximately inside a rectangle whose corners are at
* 1 (x_start, y_start)
* 2 (x_start + width*cos(angle), y_start + width*sin(angle))
* 3 (x_start + width*cos(angle) - size*sin(angle), y_start + width*sin(angle) + size*cos(angle))
* 4 (x_start - size*sin(angle), y_start + size*cos(angle))
* */
int get_text_width(char* face_path, int fontsize, char* text);
int get_text_width_utf8(char* face_path, int fontsize, char* text);
};
#endif

16
resources/attractor_2011-04-28_10-05-11-1.stf

@ -0,0 +1,16 @@
AttractorKernel: {
dimension: "3"
type: "unravel"
parameters: {
: "2.723821"
: "0.799579"
: "0.907577"
: "0.270316"
: "2.576256"
: "0.759911"
: "1.568236"
}
}
Projector: {
}

16
resources/attractor_2011-04-28_10-30-35-2.stf

@ -0,0 +1,16 @@
AttractorKernel: {
dimension: "3"
type: "unravel"
parameters: {
: "2.057414"
: "-0.082008"
: "2.960202"
: "0.191999"
: "-1.458821"
: "0.638927"
: "1.090222"
}
}
Projector: {
}

16
resources/attractor_2011-04-29_04-34-41-9.stf

@ -0,0 +1,16 @@
AttractorKernel: {
dimension: "3"
type: "unravel"
parameters: {
: "2.922310"
: "-1.248395"
: "1.987736"
: "-2.722189"
: "2.567994"
: "-2.476880"
: "2.661256"
}
}
Projector: {
}

16
resources/attractor_2011-04-29_15-19-03-9.stf

@ -0,0 +1,16 @@
AttractorKernel: {
dimension: "3"
type: "unravel"
parameters: {
: "-1.449797"
: "0.899829"
: "2.713661"
: "0.072155"
: "-1.609515"
: "-0.801832"
: "2.246601"
}
}
Projector: {
}

5
resources/myClearShader.frag

@ -0,0 +1,5 @@
uniform float fade;
void main(){
gl_FragColor = vec4(0.0, 0.0, 0.0, fade);
}

4
resources/myClearShader.vert

@ -0,0 +1,4 @@
void main( void ) {
gl_Position = gl_Vertex;
}

9
resources/myTeaShader.frag

@ -0,0 +1,9 @@
varying vec4 color;
uniform int steps;
void main( void ) {
gl_FragColor.rgb = sin(3.0*sin(normalize(color.rgb) + vec3(steps)*vec3(0.01, 0.017, 0.0093)))*0.5+0.5;
gl_FragColor.rgb *= 0.1;
gl_FragColor.a = 1.0;
}

7
resources/myTeaShader.vert

@ -0,0 +1,7 @@
varying vec4 color;
void main( void ) {
gl_Position = ftransform();
gl_Position.xyz = gl_Position.xyz*0.6 - vec3(0.0, 0.0, 0.0);
color = gl_Vertex;
}

145
shader.h

@ -0,0 +1,145 @@
#ifndef SHADER_H
#define SHADER_H
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <map>
#include <iterator>
#include <GL/glew.h>
#include <GL/freeglut.h>
class shader {
GLuint program;
std::map<GLenum, GLuint> shaders;
public:
shader(std::string vertex_shader_filename, std::string fragment_shader_filename) {
program = glCreateProgram();
if(program == 0) {
throw std::runtime_error("Program couldn't be created");
}
{
std::ifstream vertex_shader(vertex_shader_filename);
if(!vertex_shader)
throw std::runtime_error(vertex_shader_filename + " couldn't be opened");
read_shader(vertex_shader, GL_VERTEX_SHADER);
}
{
std::ifstream fragment_shader(fragment_shader_filename);
if(!fragment_shader)
throw std::runtime_error(fragment_shader_filename + " couldn't be opened");
read_shader(fragment_shader, GL_FRAGMENT_SHADER);
}
link_program();
}
~shader(){
begin();
for(auto & it : shaders){
GLuint shader = it.second;
glDetachShader(program, shader);
glDeleteShader(shader);
}
glDeleteProgram(program);
end();
}
void begin() {
glUseProgram(program);
}
void end() {
glUseProgram(0);
}
void set_uniform(char const* name, float x) {
glUniform1f(glGetUniformLocation(program, name), x);
}
void set_uniform(char const* name, float x, float y) {
glUniform2f(glGetUniformLocation(program, name), x, y);
}
void set_uniform(char const* name, float x, float y, float z) {
glUniform3f(glGetUniformLocation(program, name), x, y, z);
}
void set_uniform(char const* name, float x, float y, float z, float w) {
glUniform4f(glGetUniformLocation(program, name), x, y, z, w);
}
void set_uniform(char const* name, int x) {
glUniform1i(glGetUniformLocation(program, name), x);
}
void set_uniform(char const* name, int x, int y) {
glUniform2i(glGetUniformLocation(program, name), x, y);
}
void set_uniform(char const* name, int x, int y, int z) {
glUniform3i(glGetUniformLocation(program, name), x, y, z);
}
void set_uniform(char const* name, int x, int y, int z, int w) {
glUniform4i(glGetUniformLocation(program, name), x, y, z, w);
}
private:
void read_shader(std::istream& file, GLenum type) {
// get the c-string
std::string buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
const char* sptr = buffer.c_str();
int ssize = buffer.size();
// create and compile shader
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &sptr, &ssize);
glCompileShader(shader);
// check compile status
GLint status = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(status == GL_FALSE || shader == 0) {
GLsizei infoLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
char* infoBuffer = new GLchar[infoLength];
glGetShaderInfoLog(shader, infoLength, &infoLength, infoBuffer);
std::cerr << buffer << std::endl;
std::cerr << "shader reports:\n" << infoBuffer << std::endl;
delete [] infoBuffer;
throw std::runtime_error("Shader failed to compile");
}
// put it in tha map
shaders[type] = shader;
}
void link_program() {
// attach all shaders
for(auto & it : shaders) {
GLuint shader = it.second;
glAttachShader(program, shader);
}
// link
glLinkProgram(program);
// check link status
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if(status == GL_FALSE) {
throw std::runtime_error("Shader failed to link");
}
}
};
#endif // SHADER_H

11
stfu/ExampleProgramOutput.stf

@ -0,0 +1,11 @@
Screen options: {
Brightness: "1.5"
Contrast: "70.1"
heigth: "1200"
rendermode: "OpenGL"
width: "1920"
}
Sound options: {
max soundfx: "128"
outputmode: "5.1"
}

28
stfu/LICENSE.txt

@ -0,0 +1,28 @@
Copyright (c) 2009 Maurice Bos and Nick Overdijk
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Maurice Bos (maurice@bosbyte.nl)
- Nick Overdijk (nick@dotsimplicity.net)

45
stfu/STFU.cbp

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="STFU" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
<Option output="bin\Debug\STFU" prefix_auto="1" extension_auto="1" />
<Option object_output="obj\Debug\" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-Wall" />
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release">
<Option output="bin\Release\SSSParser" prefix_auto="1" extension_auto="1" />
<Option object_output="obj\Release\" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
</Compiler>
<Unit filename="main.cpp" />
<Unit filename="stf.cpp" />
<Unit filename="stf.hpp" />
<Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
</Extensions>
</Project>
</CodeBlocks_project_file>

21
stfu/STFU.depend

@ -0,0 +1,21 @@
# depslib dependency file v1.0
1241021944 source:/media/Data/Code/C/AwesomeAttractor/stfu/main.cpp
<iostream>
<fstream>
"stf.hpp"
1241022258 /media/Data/Code/C/AwesomeAttractor/stfu/stf.hpp
<fstream>
<string>
<sstream>
<map>
<stdexcept>
1241019586 source:/media/Data/Code/C/AwesomeAttractor/stfu/stf.cpp
<iostream>
<fstream>
<map>
<string>
<typeinfo>
"stf.hpp"

26
stfu/STF_Format_Example.stf

@ -0,0 +1,26 @@
imthefirst: "The first value!"
name with spaces: "Names can contain spaces"
name
with
newlines: "And even newlines!"
test: {
blah: "The value of [root].test.blah"
newlines: "newlines and all their whitespace
get stored"
comment: This comment value contains some information about how to comment in SSS files.
"You can place comment before the quotes, the parser will ignore it."
output this: "This particular value is retrieved in the code."
output child:
Same goes for children. The parser ignores anything until a curly bracket is found. {
info: "Awwwwwwright! Tree output oh yeah."
coolness: "+20"
}
Array: { :"This" :"is" :"like" :"an" :"array" }
2D array:
{
: { :"First" :"Row" }
: { :"Second" :"Row" :"!" }
}
}

6
stfu/arrays.stf

@ -0,0 +1,6 @@
array: { :"Some" :"Unnamed" :"Values" }
2D array:
{
: { :"First" :"Row" }
: { :"Second" :"Row" :"!" }
}

282
stfu/main.cpp

@ -0,0 +1,282 @@
#include <iostream>
#include <fstream>
#include "stf.hpp"
using namespace std;
using stfu::node;
/*! \author Nick Overdijk
* \version 1.2
* \date 2009-04-27
*
* STFU Example App
*/
void prettyprint(const string &title) {
cout
<< "\t\t-----" << title << "-----\t\t\n"
<< endl;
}
void read_examples(node &n) {
prettyprint("Reading Examples");
cout
<< "Reading a STF file in a node is trivial with the stream insertion operator, it returns whether it had success: true/false\n"
<< endl;
if ("test.stf" >> n) {
prettyprint("Outputting a node/tree");
cout << n;
cout
<< "\n\nnode::getChild() returns a node&, so we can easily output nested nodes:\n"
<< endl;
cout << n.getChild("child");
cout
<< "\n\nnode::getValue() returns a string&, so we can easily output values too:\n"
<< endl;
cout << n.getValue("imthefirst");
cout
<< "\n\nThe constness of getChild and getValue depend on the object."
<< endl;
} else {
cerr << "Couldn't read file!" << endl;
}
}
void change_examples(node &n) {
cout
<< "\t\t-----Change examples------\t\t\n"
<< endl;
if ("test.stf" >> n) {
prettyprint("Edit a value");
cout << "Before:" << endl;
cout << n;
n.value("imthefirst") = "O YEAH!";
cout << "After: " << endl;
cout << n;
prettyprint("Edit a node");
cout << "Before:" << endl;
cout << n;
n.child("child") = n;
cout << "After: " << endl;
cout << n;
prettyprint("Edit the name of a value");
cout << "Before:" << endl;
cout << n;
n.renameValue("imthefirst", "roflolmao");
cout << "After: " << endl;
cout << n;
prettyprint("Edit the name of a child");
cout << "Before:" << endl;
cout << n;
n.renameChild("child", "NEW NAMEZ");
cout << "After: " << endl;
cout << n;
} else {
cerr << "Couldn't read file!" << endl;
}
}
void create_examples(node &n) {
prettyprint("Creation examples");
node screenoptions;
node soundoptions;
if (!("screenoptions.stf" >> screenoptions && "soundoptions.stf" >> soundoptions)) {
cerr << "Couldn't read files!" << endl;
return;
}
cout << "You can merge these two tree quite easily into one tree (aka \"Adding children\"):" << endl;
cout << "Before (screenoptions):" << endl;
cout << screenoptions << endl;
cout << "Before (soundoptions):" << endl;
cout << soundoptions << endl;
//child() creates the child when it doesn't exist
n.child("Screen options") = screenoptions;
//but you can do this too
n.addChild("Sound options", soundoptions);
cout << "After (both are now children of options):" << endl;
cout << n;
prettyprint("Adding a value");
cout << "Before:" << endl;
cout << n;
//this way, NOT sure child() won't create a child (if it doesn't exist, it'll create it)
//also not sure value() won't alter a value (if the value[index] exists, it'll change that)
n.child("Screen options").value("Contrast") = "70.1";
//this way, 100% sure that getChild() won't create a child, and addValue() will always add a value
//get{Child|Value} throw an out_of_range when they can't find the {Child|Value}.
n.getChild("Screen options").addValue("Brightness") = "1.5";
cout << "After:" << endl;
cout << n;
prettyprint("Writing to a file (aka \"Saving to a file\")");
const char *filename = "ExampleProgramOutput.stf";
if (!(filename << n)) {
cerr << "Couldn't write to ";
} else {
cout << "Node succesfully saved to ";
}
cout << filename << endl << endl;
}
void remove_examples(node &n) {
prettyprint("Removal examples");
if (!("test.stf" >> n)) {
cerr << "Couldn't open file!" << endl;
}
prettyprint("Deleting a value");
cout << "Before:" << endl;
cout << n;
//remove{Child|Value} throws an out_of_range when the child/value isn't found
n.removeValue("imthefirst");
cout << "After:" << endl;
cout << n;
prettyprint("Deleting a child/node");
cout << "Before:" << endl;
cout << n;
n.removeChild("child");
cout << "After:" << endl;
cout << n;
}
void array_examples(node &n) {
prettyprint("Array Examples");
if (!("arrays.stf" >> n)) {
cerr << "Couldn't open arrays.stf!" << endl;
return;
}
prettyprint("Iterating over an array: try/catch method");
node &array = n.getChild("array");
try {
size_t i = 0;
while (true) {
//use getValue(), it throws an out_of_range when there are no more elements
cout << array.getValue(i) << endl;
i++;
}
} catch (out_of_range &e) {/*we're done! ;-)*/}
prettyprint("Iterating over an array: size() method");
size_t max = array.values.size();
for(size_t i = 0; i < max; i++){
cout << array.getValue(i) << endl;
}
prettyprint("Iterating over a 2D-array: size() method");
node &multiarray = n.getChild("2D array");
//rows are children
size_t rows = multiarray.children.size();
//each row can have a different amount of cols
size_t cols[rows];
for(size_t i = 0; i < rows; i++){
//same as with size() method above
cols[i] = multiarray.getChild(i).values.size();
//output to see it for yourself
cout << i << ',' << cols[i] << endl;
}
//so, we're done. Code could've been written in 100 ways, but this does it step by step to be clear.
for(size_t row = 0; row < rows; row++){
for(size_t col = 0; col < cols[row]; col++){
cout << multiarray.getChild(row).getValue(col) << ", ";
}
cout << "\b\b " << endl;
}
/*Arrays are simply unnamed nodes/values. Nothing more, nothing less.
You can change them like nodes/values, add them the same way, etc.
Most of the functions are overloaded so that you don't have to specify a name
These functions call their overloaded brethren with name = "" */
prettyprint("Creating an array");
cout << "Before:\n\n";
cout << n << endl;
node &newarray = n.addChild("my new array");
stringstream buf;
for(size_t i = 0; i < 10; i++){
buf << i;
newarray.addValue() = buf.str();
}
cout << "After:\n\n";
cout << n << endl;
}
int main() {
prettyprint("Welcome to the stf example app");
ifstream license("LICENSE.txt");
if (license.good()) {
string line;
while (getline(license, line)) {
cout << line << endl;
}
license.close();
} else {
cerr << "Couldn't open/read LICENSE.txt" << endl;
exit(-1);
}
cout << endl;
cout
<< "This application shows how easy it is to use STFU (Simple Tree File Utility).\n"
<< "STF is a \"new\" way to store leveled data, just as XML can do, for example.\n"
<< "The format looks like a C(++) struct, which we think is easier to read than XML.\n"
<< "Each {...} is a node, a node has other nodes and values. The file itself is the\n"
<< "(unnamed) root node.\n"
<< endl;
//create an empty node
node n;
read_examples(n);
n.clear();
change_examples(n);
n.clear();
create_examples(n);
n.clear();
remove_examples(n);
n.clear();
array_examples(n);
n.clear();
return 0;
}

4
stfu/screenoptions.stf

@ -0,0 +1,4 @@
width: "1920"
heigth: "1200"
rendermode: (OpenGL or DirectX) "OpenGL"

107
stfu/simple documentation.html

@ -0,0 +1,107 @@
<h1>STF - Simple Tree Format</h1>
<p>
STF is a new file format to store a tree of values, just like XML and JSON can do. It has support for only 2 types: values and nodes. A node can have values and other nodes, allowing the creation of a tree format. A STF file itself is a node (the virtual root node). Nodes are a collection of other values and (child)nodes.
</p>
<h2>Usage</h2>
<p>
Nodes and values are named, the smallest name being "". We refer to the nodes with "" as name as unnamed nodes/values, but the same rules apply for the syntax; examples will follow, don't worry. Each name is followed by a ':' which signifies the end of the name (the name-terminator). The ':' is followed by either a '{' or a '"', which signifies the type of the name (the type-specifier): '{' are lists, '"' are values. The parser will extract and ignore anything in between the name-terminator and the type-specifier.
</p>
<h2>Examples</h2>
<h3>Starting easy</h3>
<p>
Here's an example of a very small STF file. It shows values and nodes and their syntax, without fancy stuff.
<pre>
name: "First value in the file"
childnode: {
value: "This is another value, inside a child node with the name "childnode"
}
</pre>
</p>
<h3>Comments</h3>
<p>
Don't want to have a very long descriptive name, but do want a bit of extra info? Comments (or anything really) can be place in between the name-terminator and the type-specifier.
<pre>
name: This text will be ignore by the parser "First value in the file."
childnode: This text will too, be ignored {
value: You probably already guessed it
But this text will to be ignored. Anything here is allowed, except for a type-specifier of course! ;-)
"This is another value, inside a child node with the name ""childnode""."
}
<h3>Getting more interesting</h3>
<p>
This example shows what characters are allowed inside names and values.
<pre>
firstnode: {
subnode: {
blah: "xyz"
blah: "names of values/childs don't have to be unique!"
}
}
secondnode: {
name with space: "names can contain spaces"
name
with
newlines: "names can contain newlines"
blah: "values can contain
newlines too!"
}
</pre>
</p>
<p>
NOTE: Take a look at the other .stf files included with this project for more examples.
</p>
<h1>STFU - Simple Tree Format Utility</h1>
<p>
STFU is the first C++ implementation for STF.
</p>
<p>
This example will show you some of the basic features of STFU:
<pre>
#include <iostream>
#include "stf.hpp"
using namespace std;
using stfu::node;
int main(){
node n,f;
if (n.read("blah.stf")){ //could also do: 'if ("blah.stf" >> n){'
cout << n.value("test"); // Read a value
cout << n.child("subnode").value("hi",0); //Read the first value
cout << n.child("subnode").value("hi",1); //Read the second value
n.child("subnode").value("test") = "blah"; //Add a value
if (f.read("another_file.stf")){
n.child("secondnode") = f; //add a child
}
n.write("blah.stf"); //Write changes back to the file
// "blah.stf" << n; would also be valid.
cout << n; //output the file to the console instead of a file.
} else {
cout << "ERROR!" << endl;
}
}
//NOTE: For more detailed examples, please take a look at the 'main.cpp' file of this project.
</pre>
</p>
<p>
As you see, the .child() and .value() functions can be used to read, create and change values/childs. More advanced functions are available, 'main.cpp' contains examples to explain all of them.
</p>

9
stfu/soundoptions.stf

@ -0,0 +1,9 @@
max soundfx:
A value between 0 and 255
"128"
outputmode:
Options are: 2.0, 4.0, 4.1, 5.1, 7.1 and 412.28
"5.1"

272
stfu/stf.cpp

@ -0,0 +1,272 @@
/*
Copyright (c) 2009 Maurice Bos and Nick Overdijk
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Maurice Bos (maurice@bosbyte.nl)
- Nick Overdijk (nick@dotsimplicity.net)
*/
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <typeinfo>
#include "stf.hpp"
namespace stfu {
std::ostream& operator<< (std::ostream& out, const node& root) {
root.write(out);
return out;
}
bool operator<< (const char* filename, const node& root) {
return root.write(filename);
}
std::istream& operator>> (std::istream& in, node& root) {
root.read(in);
return in;
}
bool operator>> (const char* filename, node& root) {
return root.read(filename);
}
const std::string& node::getValue(const std::string& name, size_t index) const throw(std::out_of_range) {
return get_indexed<std::string, std::string>(values, name, index);
}
/*Function is const, but shouldn't be called on const objects since it returns a nonconst-reference to a member*/
std::string& node::getValue(const std::string& name, size_t index) throw(std::out_of_range) {
return get_indexed<std::string, std::string>(values, name, index);
}
std::string& node::addValue(const std::string& name) {
return values.insert(std::pair<std::string, std::string>(name, std::string()))->second;
}
std::string& node::value(const std::string& name, size_t index) {
try {
return getValue(name, index);
} catch(std::out_of_range& e) {
//it doesn't exist: create it
return addValue(name);
}
}
void node::removeValue(const std::string& name, size_t index) throw(std::out_of_range) {
values.erase(get_indexed_it(values, name, index));
return;
}
void node::renameValue(const std::string& oldName, const std::string& newName, size_t index) {
addValue(newName) = value(oldName, index);
removeValue(oldName, index);
}
const node& node::getChild(const std::string& name, size_t index) const throw(std::out_of_range) {
return get_indexed<std::string, node>(children, name, index);
}
node& node::getChild(const std::string& name, size_t index) throw(std::out_of_range) {
return get_indexed<std::string, node>(children, name, index);
}
node& node::addChild(const std::string& name) {
return children.insert(std::pair<std::string, node>(name, node()))->second;
}
node& node::addChild(const std::string& name, node& newNode) {
return children.insert(std::pair<std::string, node>(name, newNode))->second;
}
node& node::child(const std::string& name, size_t index) {
//if there's no such child, add one
try {
return getChild(name, index);
} catch(std::out_of_range& e) {
//it doesn't exist: create it
return addChild(name);
}
}
void node::renameChild(const std::string& oldName, const std::string& newName, size_t index) {
node copy = child(oldName, index);
removeChild(oldName, index);
addChild(newName) = copy;
}
void node::removeChild(const std::string& name, size_t index) throw(std::out_of_range) {
children.erase(get_indexed_it(children, name, index));
return;
}
bool node::read(const char* filename) {
std::ifstream f(filename);
if(!f.good()) return false;
bool success = read(f);
f.close();
return success;
}
bool node::read(std::istream& in) {
while(1) {
in >> std::ws; //Skip whitespace
//if end of node is reached, return
if(in.peek() == '}') {
in.ignore();
return true;
}
if(in.eof()) {
return true; //End of the file is reached
}
std::string name;
char type; // '{' or '"'
streamRead(in, name, ':'); //Read name (all chars before ':')
type = streamSkip(in,"\"{"); //Skip everything until '{' or '"'
switch(type) {
//in case of value
case '"': {
std::string value;
while(1) {
if(streamRead(in, value, '"') == 0) { //Read to the closing-"
return false;
}
if(in.peek() == '"') {
in.ignore();
value += '"';
continue;
} else {
break;
}
}
this->values.insert(std::pair<std::string,std::string>(name, value));
break;
}
//in case of child
case '{': {
node sub;
if(!sub.read(in)) { //Recursively read the subnode
return false;
}
this->children.insert(std::pair<std::string,node>(name,sub));
break;
}
default:
return false;
}
}
}
/*Writes to a file using it's overloaded self*/
bool node::write(const char* filename) const {
std::ofstream f(filename);
if(!f.good()) {
return false;
}
bool success = write(f);
f.close();
return success;
}
// TODO (Nick#1#): Make write() not put unnamed values on a new line, children are okay.
bool node::write(std::ostream& out, size_t depth, std::string indent) const {
std::string indentation;
for(size_t i = 0; i < depth; i++) {
indentation += indent;
}
for(std::multimap<std::string, std::string>::const_iterator value_it = values.begin(); value_it != values.end(); value_it++) {
//Escape all the '"' by adding a second '"'
std::string value(value_it->second);
size_t found = value.find('"');
//while there are more ", insert second "s
while(found != value.npos) {
value.insert(found, 1, '"');
found = value.find('"', found+2);
}
out << indentation << value_it->first << ": \"" << value << '"' << std::endl;
}
for(std::multimap<std::string, node>::const_iterator child_it = children.begin(); child_it != children.end(); child_it++) {
out << indentation << child_it->first << ": {" << std::endl;
child_it->second.write(out, depth+1);
out << indentation << '}' << std::endl;
}
return true;
}
char node::streamSkip(std::istream& in, const std::string& delimiters) {
char cur;
//Return if the current char is part of delimiters[]
while(in >> std::noskipws >> cur) {
if(delimiters.find_first_of(cur) != delimiters.npos) return cur;
}
return 0;
}
char node::streamRead(std::istream& in, std::string& out, const std::string& delimiters) {
char cur;
//Return if the current char is part of delimiters[]
while(in >> std::noskipws >> cur) {
if(delimiters.find(cur) != delimiters.npos) return cur;
out += cur;
}
return 0;
}
char node::streamRead(std::istream& in, std::string& out, const char delimiter) {
char cur;
//Return if the current char is delimiter
while(in >> std::noskipws >> cur) {
if(delimiter == cur) return cur;
out += cur;
}
return 0;
}
}

358
stfu/stf.hpp

@ -0,0 +1,358 @@
/*
Copyright (c) 2009 Maurice Bos and Nick Overdijk
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- Maurice Bos (maurice@bosbyte.nl)
- Nick Overdijk (nick@dotsimplicity.net)
*/
#include <fstream>
#include <string>
#include <sstream>
#include <map>
#include <stdexcept>
#ifndef STFU_HPP
#define STFU_HPP
namespace stfu {
const static std::string not_found("search->No such child/value");
/*! \class node
* \brief A node in an STF tree.
* \author Maurice Bos
* \author Nick Overdijk
* \version 1.0
* \date 2009-04-25
*
* When you read an STF file through a node (with read() for example), this node will be the root node, without a name. See the examples for more information.
*/
class node {
/** Overloaded ostream's operator<< */
friend std::ostream& operator<< (std::ostream& out, const node& root);
/** Acts like write(), but looks like this: "filename" << node */
friend bool operator<< (const char* filename, const node& root);
/** Overloaded istream's operator>> */
friend std::istream& operator>> (std::istream& in, node& root);
/** Acts like read(), but looks like this: "filename" >> node */
friend bool operator>> (const char* filename, node& root);
public:
//@{
/** The values and children belonging to this node. To add, remove, do whatever: you CAN use these variables directly. To use indexing, use the member functions below*/
std::multimap<std::string, std::string> values;
std::multimap<std::string, node> children;
//@}
node() : values(), children() {}
/**
Clears the whole node recursively.
*/
void clear() {
values.clear();
children.clear();
}
/**
Gets the std::string value from a variable
\param name The name of the value you wish to retrieve
\param index If there are more values with the same name, they are indexed. Here you can supply its indexnumber.
\return The retrieved value
*/
std::string& value(const std::string& name, size_t index = 0);
/**
Same as value(), but for unnamed values
\note same as value("", index)
\param index If there are more unnamed values, they are indexed. Here you can supply its indexnumber.
\return Same as value
*/
std::string& value(size_t index) {
return value("", index);
}
/**
Creates and adds a value.
\param name The name of the value to be created
\return A reference to the value of the created value.
*/
std::string& addValue(const std::string& name = "");
/**
Const function for const objects to get a value. It's NOT possible to call value() on constant objects for value() isn't const.
\param name Name of the value to be retrieved
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a const std::string& to the value of value with the name and index specified
*/
const std::string& getValue(const std::string& name, size_t index) const throw(std::out_of_range);
/**
Same as getValue() const, but for unnamed values
\note same as getValue("", index) const
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
\return Returns a const std::string& to the value of value with the name and index specified
*/
const std::string& getValue(size_t index) const throw(std::out_of_range) {
return getValue("", index);
}
/**
Same as getValue() const, but for non-const objects. The returned std::string& can safely be modified.
\param name Name of the value to be retrieved
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a std::string& to the value of value with the name and index specified
*/
std::string& getValue(const std::string& name, size_t index = 0) throw(std::out_of_range);
/**
Same as getValue(), but for unnamed values
\note same as getValue("", index)
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
\return Returns a std::string& to the value of value with the name and index specified
*/
std::string& getValue(size_t index) throw(std::out_of_range) {
return getValue("", index);
}
/**
Removes a value. Surprise huh?
\param name Name of the value to be removed
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
*/
void removeValue(const std::string& name, size_t index = 0) throw(std::out_of_range);
/**
Removes an unnamed value.
\note same as removeValue("", index);
\param index If there are > 1 unnamed values, they are indexed. Here you can supply an indexnumber.
*/
void removeValue(size_t index) throw(std::out_of_range) {
removeValue("", index);
}
/**
Renames a value.
\param oldName Name of the value to be renamed
\param newName The name that the oldName-value should have
\param index If there are > 1 values with the same name, they are indexed. Here you can supply an indexnumber.
*/
void renameValue(const std::string& oldName, const std::string& newName, size_t index = 0);
/**
Changes, adds or retrieves node
\param name The name of the child you wish to retrieve, change or add.
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
\return The retrieved node
If this index number is > the number of variables with that name, a new variable with that name is created with index = current number of same name variables + 1.
So say you have 4 variables named "tree", you call child("tree", 10), another tree gets made with index 5, NOT 10.
*/
node& child(const std::string& name, size_t index = 0);
/**
Same as child(), but for unnamed children.
\note same as child("", index)
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
\return The retrieved node
*/
node& child(size_t index = 0) {
return child("", index);
}
/**
Guarranteed to add a child
\param name Name for the child
\return A reference to the created node
*/
node& addChild(const std::string& name = "");
/**
As addChild(name), but copies data from newChild as well.
\param name Name for the child
\param newChild Data to copy from the child.
\return A reference to the created node
*/
node& addChild(const std::string& name, node& newChild);
/**
As addChild(name, newChild), but without name, for unnamed children
\note same as addChild("", newChild);
\param newChild Data to copy from the child.
\return A reference to the created node
*/
node& addChild(node& newChild) {
return addChild("", newChild);
}
/**
Const function for const objects to get a node. It's NOT possible to call child() for this, for child() isn't const.
\param name Name of the child to be retrieved
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a const node& to the node with the name and index specified
*/
const node& getChild(const std::string& name, size_t index = 0) const throw(std::out_of_range);
/**
Const function for const objects to get an unnamed const node&.
\note same as getChild("", index) const;
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
\return Returns a const node& to the node with the name and index specified
*/
const node& getChild(size_t index = 0) const throw(std::out_of_range) {
return getChild("", index);
}
/**
Same as getChild() const, but for non-const objects. The returned child & can be modified
\param name Name of the child to be retrieved
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
\return Returns a node& to the node with the name and index specified
*/
node& getChild(const std::string& name, size_t index = 0) throw(std::out_of_range);
/**
Same as getChild() const, but for non-const objects.
\note same as getChild("", index);
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
\return Returns a node& to the node with the name and index specified
*/
node& getChild(size_t index = 0) throw(std::out_of_range) {
return getChild("", index);
}
/**
Removes a child. Surprise huh?
\param name Name of the child to be removed
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
*/
void removeChild(const std::string& name, size_t index = 0) throw(std::out_of_range);
/**
As removeChild() for unnamed children.
\param index If there are > 1 unnamed children, they are indexed. Here you can supply an indexnumber.
*/
void removeChild(size_t index = 0) throw(std::out_of_range) {
removeChild("", index);
}
/**
Renames a child.
\param oldName Name of the child to be renamed
\param newName The name that the oldName-child should have
\param index If there are > 1 children with the same name, they are indexed. Here you can supply an indexnumber.
*/
void renameChild(const std::string& oldName, const std::string& newName, size_t index = 0);
/**
Reads the STF from an istream
\return Returns whether it was succesful
*/
bool read(std::istream& in);
/**
Reads the STF from a file
\return Returns whether it was succesful
*/
bool read(const char* filename);
/**
Writes the STF to an ostream with optional indentation
\param out ostream to write to
\param depth how much indentation to start with
\param indent What std::string to use as indenation
\return Returns whether it was succesful
*/
bool write(std::ostream& out, size_t depth = 0, std::string indent = "\t") const;
/**
Writes to a file. Simply first opens a file and passes that ostream to itself.
\param filename File to write to
\return Returns whether it was succesful
*/
bool write(const char* filename) const;
private:
char streamRead(std::istream& in,std::string& out, const std::string& delim);
char streamRead(std::istream& in, std::string& out, const char delim);
char streamSkip(std::istream& in, const std::string& delim);
/*
returns a T2&, not a const T2&. The functions getValue/getChild make sure this will be done correctly for const objects
this function can NOT use get_indexed_it, because that function can't be const:
const_iterators can not be transformed into iterators, and the iterator is needed for erase(), which wants an iterator.
*/
template <typename T1, typename T2>
T2& get_indexed(const std::multimap<T1, T2> &container, const T1& key, size_t index = 0) const throw(std::out_of_range) {
size_t count = container.count(key);
if(count != 0 && count-1 >= index) {
typename std::multimap<T1, T2>::const_iterator it = container.find(key);
while(index--) it++;
return const_cast<T2&>(it->second);
} else {
throw std::out_of_range((std::string)"get_indexed->"+"Element " + key + " doesn't exist!");
}
}
// template <typename T1, typename T2>
// typename multimap<T1, T2>::iterator get_indexed_it(multimap<T1, T2> &container, const T1 &key, size_t index = 0) throw (out_of_range) {
// size_t count = container.count(key);
//
// if (count != 0 && count-1 >= index) {
// typename multimap<T1, T2>::iterator it = container.find(key);
// while (index--) it++;
// return it;
// } else {
// throw out_of_range((std::string)"get_indexed_it->"+"Element " + key + "doesn't exist!");
// }
// }
template <typename Container, typename T>
typename Container::iterator get_indexed_it(Container& container, const T& key, size_t index = 0)
throw(std::out_of_range) {
typename Container::iterator it = container.find(key);
while(index-- && it != container.end() && it->first==key) it++;
if(it == container.end()) throw std::out_of_range("get_indexed_it(Container&, const T&, size_t)");
return it;
}
};
typedef std::pair<std::string, std::string> value;
typedef std::pair<std::string, node> child;
typedef std::multimap<std::string, std::string>::iterator valueiterator;
typedef std::multimap<std::string, node>::iterator childiterator;
}
#endif // STFU_HPP

4
stfu/test.stf

@ -0,0 +1,4 @@
imthefirst: "The first value inside root!"
child: {
blah: "The value of [root].child.blah"
}