Joshua Moerman
14 years ago
commit
ab5a50bb97
29 changed files with 6941 additions and 0 deletions
@ -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
|
@ -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> |
@ -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
|
@ -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; |
|||
} |
|||
|
|||
|
@ -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 |
|||
|
|||
|
|||
|
File diff suppressed because it is too large
@ -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 |
|||
|
@ -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: { |
|||
} |
|||
|
@ -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: { |
|||
} |
|||
|
@ -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: { |
|||
} |
|||
|
@ -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: { |
|||
} |
|||
|
@ -0,0 +1,5 @@ |
|||
uniform float fade; |
|||
|
|||
void main(){ |
|||
gl_FragColor = vec4(0.0, 0.0, 0.0, fade); |
|||
} |
@ -0,0 +1,4 @@ |
|||
|
|||
void main( void ) { |
|||
gl_Position = gl_Vertex; |
|||
} |
@ -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; |
|||
} |
@ -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; |
|||
} |
@ -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
|
@ -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" |
|||
} |
@ -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) |
|||
|
@ -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> |
@ -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" |
|||
|
@ -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" :"!" } |
|||
} |
|||
} |
@ -0,0 +1,6 @@ |
|||
array: { :"Some" :"Unnamed" :"Values" } |
|||
2D array: |
|||
{ |
|||
: { :"First" :"Row" } |
|||
: { :"Second" :"Row" :"!" } |
|||
} |
@ -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; |
|||
} |
@ -0,0 +1,4 @@ |
|||
|
|||
width: "1920" |
|||
heigth: "1200" |
|||
rendermode: (OpenGL or DirectX) "OpenGL" |
@ -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> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
@ -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" |
|||
|
@ -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; |
|||
} |
|||
|
|||
} |
@ -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
|
@ -0,0 +1,4 @@ |
|||
imthefirst: "The first value inside root!" |
|||
child: { |
|||
blah: "The value of [root].child.blah" |
|||
} |
Reference in new issue