# HG changeset patch # User John Tsiombikas # Date 1355607783 -7200 # Node ID cfe68befb7cc2d1b0478d3984134c52345710c25 # Parent e4818a3300b93d9c6a83a5c62aefa9f6041c959f some progress diff -r e4818a3300b9 -r cfe68befb7cc .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,4 @@ +\.o$ +\.d$ +\.swp$ +^blobo$ diff -r e4818a3300b9 -r cfe68befb7cc Makefile --- a/Makefile Sat Dec 15 07:52:13 2012 +0200 +++ b/Makefile Sat Dec 15 23:43:03 2012 +0200 @@ -4,7 +4,7 @@ bin = blobo CXXFLAGS = -ansi -pedantic -Wall -g -LDFLAGS = $(libgl) +LDFLAGS = $(libgl) -lvmath -limago ifeq ($(shell uname -s), Darwin) libgl = -framework OpenGL -framework GLUT -lGLEW diff -r e4818a3300b9 -r cfe68befb7cc RUN --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RUN Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,3 @@ +#!/bin/sh + +./blobo -world 100x100x32 -genscale 10 $* diff -r e4818a3300b9 -r cfe68befb7cc src/camera.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/camera.cc Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,237 @@ +#include "opengl.h" +#include "camera.h" + +Camera::Camera() +{ + inval_cache(); +} + +Camera::~Camera() +{ +} + +void Camera::calc_inv_matrix(Matrix4x4 *mat) const +{ + *mat = matrix().inverse(); +} + +void Camera::set_glmat(const Matrix4x4 &mat) const +{ +#ifdef SINGLE_PRECISION_MATH + if(glLoadTransposeMatrixfARB) { + glLoadTransposeMatrixfARB((float*)&mat); + } else { + Matrix4x4 tmat = mat.transposed(); + glLoadMatrixf((float*)&tmat); + } +#else + if(glLoadTransposeMatrixdARB) { + glLoadTransposeMatrixdARB((double*)&mat); + } else { + Matrix4x4 tmat = mat.transposed(); + glLoadMatrixd((double*)&tmat); + } +#endif +} + +const Matrix4x4 &Camera::matrix() const +{ + if(!mcache.valid) { + calc_matrix(&mcache.mat); + mcache.valid = true; + } + return mcache.mat; +} + +const Matrix4x4 &Camera::inv_matrix() const +{ + if(!mcache_inv.valid) { + calc_inv_matrix(&mcache_inv.mat); + mcache_inv.valid = true; + } + return mcache_inv.mat; +} + +void Camera::use() const +{ + set_glmat(matrix()); +} + +void Camera::use_inverse() const +{ + set_glmat(inv_matrix()); +} + +void Camera::input_move(float x, float y, float z) +{ +} + +void Camera::input_rotate(float x, float y, float z) +{ +} + +void Camera::input_zoom(float factor) +{ +} + + +// ---- orbit camera ---- + +OrbitCamera::OrbitCamera() +{ + theta = 0.0; + phi = 0.0; + rad = 10.0; + + min_phi = -M_PI / 2; + max_phi = M_PI / 2; +} + +OrbitCamera::~OrbitCamera() +{ +} + +void OrbitCamera::set_distance(float dist) +{ + rad = dist; +} + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +void OrbitCamera::set_vertical_limits(float a, float b) +{ + a = M_PI * a / 180.0; + b = M_PI * b / 180.0; + min_phi = MIN(a, b); + max_phi = MAX(a, b); +} + +void OrbitCamera::calc_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->translate(Vector3(0, 0, -rad)); + mat->rotate(Vector3(phi, 0, 0)); + mat->rotate(Vector3(0, theta, 0)); +} + +void OrbitCamera::calc_inv_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->rotate(Vector3(0, theta, 0)); + mat->rotate(Vector3(phi, 0, 0)); + mat->translate(Vector3(0, 0, -rad)); +} + +void OrbitCamera::input_rotate(float x, float y, float z) +{ + theta += x; + phi += y; + + if(phi < min_phi) + phi = min_phi; + if(phi > max_phi) + phi = max_phi; + + inval_cache(); +} + +void OrbitCamera::input_zoom(float factor) +{ + rad += factor; + if(rad < 0.0) + rad = 0.0; + + inval_cache(); +} + +void FpsCamera::calc_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->translate(Vector3(pos.x, pos.y, pos.z)); + mat->rotate(Vector3(0, theta, 0)); + mat->rotate(Vector3(phi, 0, 0)); +} + +void FpsCamera::calc_inv_matrix(Matrix4x4 *mat) const +{ + mat->reset_identity(); + mat->rotate(Vector3(phi, 0, 0)); + mat->rotate(Vector3(0, theta, 0)); + mat->translate(Vector3(-pos.x, -pos.y, -pos.z)); +} + +void FpsCamera::input_move(float x, float y, float z) +{ + pos.x += x * cos(theta) - z * sin(theta); + pos.z += x * sin(theta) + z * cos(theta); + pos.y += y; + inval_cache(); +} + +const Vector3 &FpsCamera::get_position() const +{ + return pos; +} + + +FlyCamera::FlyCamera() +{ + pos.z = 10.0f; +} + +void FlyCamera::calc_matrix(Matrix4x4 *mat) const +{ + /*mat->reset_identity(); + mat->translate(-pos); + *mat = *mat * Matrix4x4(rot.get_rotation_matrix()); + mat->translate(pos);*/ + //mat->translate(-pos.transformed(rot)); + + Matrix3x3 qmat = rot.get_rotation_matrix(); + + Vector3 ivec = qmat.get_row_vector(0); + Vector3 jvec = qmat.get_row_vector(1); + Vector3 kvec = qmat.get_row_vector(2); + + *mat = Matrix4x4(qmat); + /*Vector3 trans_x = ivec * pos; + Vector3 trans_y = jvec * pos; + Vector3 trans_z = kvec * pos; + Vector3 trans = trans_x + trans_y + trans_z;*/ + Vector3 trans; + trans.x = dot_product(ivec, pos); + trans.y = dot_product(jvec, pos); + trans.z = dot_product(kvec, pos); + mat->set_column_vector(-trans, 3); +} + +/*void FlyCamera::calc_inv_matrix(Matrix4x4 *mat) const +{ + mat->set_translation(pos); + *mat = *mat * Matrix4x4(rot.get_rotation_matrix()); +}*/ + +const Vector3 &FlyCamera::get_position() const +{ + return pos; +} + +const Quaternion &FlyCamera::get_rotation() const +{ + return rot; +} + +void FlyCamera::input_move(float x, float y, float z) +{ + pos += Vector3(x, y, z); + inval_cache(); +} + +void FlyCamera::input_rotate(float x, float y, float z) +{ + Vector3 axis(x, y, z); + float axis_len = axis.length(); + rot.rotate(axis / axis_len, axis_len); + rot.normalize(); + inval_cache(); +} diff -r e4818a3300b9 -r cfe68befb7cc src/camera.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/camera.h Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,87 @@ +#ifndef CAMERA_H_ +#define CAMERA_H_ + +#include "vmath/vmath.h" + +class Camera { +protected: + mutable struct { + bool valid; + Matrix4x4 mat; + } mcache, mcache_inv; + + virtual void calc_matrix(Matrix4x4 *mat) const = 0; + virtual void calc_inv_matrix(Matrix4x4 *mat) const; + + void inval_cache() { mcache.valid = mcache_inv.valid = false; } + void set_glmat(const Matrix4x4 &m) const; + +public: + Camera(); + virtual ~Camera(); + + const Matrix4x4 &matrix() const; + const Matrix4x4 &inv_matrix() const; + + void use() const; + void use_inverse() const; + + // these do nothing, override to provide input handling + virtual void input_move(float x, float y, float z); + virtual void input_rotate(float x, float y, float z); + virtual void input_zoom(float factor); +}; + +class OrbitCamera : public Camera { +protected: + float theta, phi, rad; + float min_phi, max_phi; + + void calc_matrix(Matrix4x4 *mat) const; + void calc_inv_matrix(Matrix4x4 *mat) const; + +public: + OrbitCamera(); + virtual ~OrbitCamera(); + + void set_distance(float dist); + void set_vertical_limits(float a, float b); + + void input_rotate(float x, float y, float z); + void input_zoom(float factor); +}; + +class FpsCamera : public OrbitCamera { +protected: + Vector3 pos; + + void calc_matrix(Matrix4x4 *mat) const; + void calc_inv_matrix(Matrix4x4 *mat) const; + +public: + void input_move(float x, float y, float z); + + const Vector3 &get_position() const; +}; + + +class FlyCamera : public Camera { +private: + Vector3 pos; + Quaternion rot; + + void calc_matrix(Matrix4x4 *mat) const; + //void calc_inv_matrix(Matrix4x4 *mat) const; + +public: + FlyCamera(); + + const Vector3 &get_position() const; + const Quaternion &get_rotation() const; + + void input_move(float x, float y, float z); + void input_rotate(float x, float y, float z); +}; + + +#endif // CAMERA_H_ diff -r e4818a3300b9 -r cfe68befb7cc src/game.cc --- a/src/game.cc Sat Dec 15 07:52:13 2012 +0200 +++ b/src/game.cc Sat Dec 15 23:43:03 2012 +0200 @@ -1,19 +1,89 @@ #include "game.h" #include "opengl.h" +#include "level.h" +#include "renderer.h" +#include "camera.h" + +bool keystate[256]; +bool bnstate[16]; + +static Level *level; +static Renderer *rend; +static FpsCamera cam; bool game_init() { + printf("initializing OpenGL state\n"); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + + printf("initializing renderer\n"); + rend = new Renderer; + rend->init(); + + printf("generating level\n"); + level = new Level; + level->generate(); + + cam.input_move(0, 2, 2); + cam.input_rotate(0, M_PI / 5, 0); + return true; } void game_shutdown() { + delete rend; + delete level; } void game_iter(double dt) { + float offs = 0.05 * dt; + float dx = 0, dy = 0; + + // handle key input + if(keystate['w'] || keystate['W']) { + dy -= offs; + } + if(keystate['s'] || keystate['S']) { + dy += offs; + } + if(keystate['d'] || keystate['D']) { + dx += offs; + } + if(keystate['a'] || keystate['A']) { + dx -= offs; + } + + cam.input_move(dx, 0, dy); } void game_render() { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + float lpos[] = {-1, 1, 2, 0}; + glLightfv(GL_LIGHT0, GL_POSITION, lpos); + + cam.use_inverse(); + + rend->render(level); } + +void game_input_shoot(int bn) +{ +} + +void game_input_move(float x, float y, float z) +{ + cam.input_move(x, y, z); +} + +void game_input_rot(float x, float y) +{ + cam.input_rotate(x * 6.0, y * 6.0, 0); +} diff -r e4818a3300b9 -r cfe68befb7cc src/game.h --- a/src/game.h Sat Dec 15 07:52:13 2012 +0200 +++ b/src/game.h Sat Dec 15 23:43:03 2012 +0200 @@ -1,7 +1,11 @@ #ifndef GAME_H_ #define GAME_H_ -bool keystate[256]; +#define GAME_MAX_KEYS 256 +#define GAME_MAX_BUTTONS 16 + +extern bool keystate[GAME_MAX_KEYS]; +extern bool bnstate[GAME_MAX_BUTTONS]; bool game_init(); void game_shutdown(); @@ -9,4 +13,8 @@ void game_iter(double dt); void game_render(); +void game_input_shoot(int bn); +void game_input_move(float x, float y, float z); +void game_input_rot(float x, float y); + #endif // GAME_H_ diff -r e4818a3300b9 -r cfe68befb7cc src/level.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/level.cc Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,64 @@ +#include "level.h" + +#include "opt.h" + +Level::Level() +{ + terrain = 0; +} + +Level::~Level() +{ + delete terrain; +} + +void Level::generate() +{ + delete terrain; + + int xsz = opt.world_size[0]; + int ysz = opt.world_size[1]; + int zsz = opt.world_size[2]; + + terrain = new Volume(xsz, ysz, zsz); + + for(int i=0; iset_voxel(i, j, k, voxel); + } + } + } +} + +bool Level::load(const char *fname) +{ + return false; +} + +bool Level::save(const char *fname) const +{ + return false; +} diff -r e4818a3300b9 -r cfe68befb7cc src/level.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/level.h Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,21 @@ +#ifndef LEVEL_H_ +#define LEVEL_H_ + +#include +#include "volume.h" + +class Level { +public: + Volume *terrain; + std::vector blobs; + + Level(); + ~Level(); + + void generate(); + + bool load(const char *fname); + bool save(const char *fname) const; +}; + +#endif // LEVEL_H_ diff -r e4818a3300b9 -r cfe68befb7cc src/main.cc --- a/src/main.cc Sat Dec 15 07:52:13 2012 +0200 +++ b/src/main.cc Sat Dec 15 23:43:03 2012 +0200 @@ -1,10 +1,12 @@ #include #include +#include #include "opengl.h" #include "game.h" #include "opt.h" static void disp(); +static void idle(); static void reshape(int x, int y); static void keydown(unsigned char key, int x, int y); static void keyup(unsigned char key, int x, int y); @@ -16,6 +18,9 @@ static void spacerot(int x, int y, int z); static void spacebut(int bn, int state); +static int win_xsz, win_ysz, centerx, centery; +static unsigned int prev_msec; + int main(int argc, char **argv) { glutInit(&argc, argv); @@ -25,10 +30,11 @@ } glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | (opt.stereo ? GLUT_STEREO : 0)); - glutInitWindowSize(800, 450); + glutInitWindowSize(opt.xsz, opt.ysz); glutCreateWindow("bloboland"); glutDisplayFunc(disp); + glutIdleFunc(idle); glutReshapeFunc(reshape); glutKeyboardFunc(keydown); glutKeyboardUpFunc(keyup); @@ -55,11 +61,17 @@ game_iter((msec - prev_msec) / 1000.0); - glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); game_render(); glutSwapBuffers(); + assert(glGetError() == GL_NO_ERROR); +} + +static void idle() +{ + glutPostRedisplay(); } static void reshape(int x, int y) @@ -69,6 +81,12 @@ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0); + + win_xsz = x; + win_ysz = y; + + centerx = x / 2; + centery = y / 2; } static void keydown(unsigned char key, int x, int y) @@ -87,35 +105,73 @@ exit(0); } - if(key < sizeof keystate / sizeof *keystate) { + if(key < GAME_MAX_KEYS) { keystate[key] = true; } } static void skeyup(int key, int x, int y) { - if(key < sizeof keystate / sizeof *keystate) { + if(key < GAME_MAX_KEYS) { keystate[key] = false; } } + +static int prev_x, prev_y; + static void mouse(int bn, int state, int x, int y) { + int idx = bn - GLUT_LEFT_BUTTON; + + if(idx < GAME_MAX_BUTTONS) { + bnstate[idx] = state == GLUT_DOWN; + + if(state == GLUT_DOWN) { + game_input_shoot(idx); + } + } + prev_x = x; + prev_y = y; } + static void motion(int x, int y) { + /* + int dx = x - centerx; + int dy = y - centery; + + if(!dx && !dy) { + return; + } + game_input_rot(dx * 0.5, dy * 0.5); + + glutWarpPointer(centerx, centery); + */ + int dx = x - prev_x; + int dy = y - prev_y; + + prev_x = x; + prev_y = y; + + if(bnstate[0]) { + game_input_rot((float)dx / win_xsz, (float)dy / win_ysz); + } } static void spacemove(int x, int y, int z) { + game_input_move(x * 0.1, y * 0.1, z * 0.1); } static void spacerot(int x, int y, int z) { + game_input_rot(y * 0.1, x * 0.1); } static void spacebut(int bn, int state) { + game_input_shoot(bn); } diff -r e4818a3300b9 -r cfe68befb7cc src/opt.cc --- a/src/opt.cc Sat Dec 15 07:52:13 2012 +0200 +++ b/src/opt.cc Sat Dec 15 23:43:03 2012 +0200 @@ -1,6 +1,55 @@ +#include +#include +#include #include "opt.h" +Options opt; + +static void default_opt() +{ + opt.xsz = 800; + opt.ysz = 450; + opt.stereo = false; + + opt.world_size[0] = opt.world_size[1] = 128; + opt.world_size[2] = 64; + + opt.gen_noise_scale = 1.0f; +} + bool parse_opt(int argc, char **argv) { + default_opt(); + + for(int i=1; ix\n"); + return false; + } + } else if(strcmp(argv[i], "-world") == 0) { + if(sscanf(argv[++i], "%dx%dx%d", opt.world_size, opt.world_size + 1, opt.world_size + 2) != 3) { + fprintf(stderr, "-world must be followed by xx\n"); + return false; + } + } else if(strcmp(argv[i], "-genscale") == 0) { + char *endp; + opt.gen_noise_scale = strtod(argv[++i], &endp); + if(endp == argv[i]) { + fprintf(stderr, "-genscale must be followed by a scaling factor\n"); + return false; + } + } else if(strcmp(argv[i], "-stereo") == 0) { + opt.stereo = true; + } else { + fprintf(stderr, "invalid option: %s\n", argv[i]); + return false; + } + } else { + fprintf(stderr, "unexpected argument: %s\n", argv[i]); + return false; + } + } return true; } diff -r e4818a3300b9 -r cfe68befb7cc src/opt.h --- a/src/opt.h Sat Dec 15 07:52:13 2012 +0200 +++ b/src/opt.h Sat Dec 15 23:43:03 2012 +0200 @@ -4,8 +4,14 @@ struct Options { int xsz, ysz; bool stereo; + + // initial parameters when generating new worlds + int world_size[3]; + float gen_noise_scale; }; +extern Options opt; + bool parse_opt(int argc, char **argv); #endif // OPT_H_ diff -r e4818a3300b9 -r cfe68befb7cc src/renderer.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/renderer.cc Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,106 @@ +#include "opengl.h" +#include "renderer.h" + +Renderer::Renderer() +{ + leveltex = 0; + sdrprog = 0; +} + +Renderer::~Renderer() +{ + shutdown(); +} + +bool Renderer::init() +{ + sdrprog = new SdrProg; + /*if(!sdrprog->load("sdr/bloboray.v.glsl", "sdr/bloboray.p.glsl")) { + return false; + }*/ + + leveltex = new Texture3D; + + return true; +} + +void Renderer::shutdown() +{ + delete leveltex; + delete sdrprog; +} + +static void draw_cube(const Vector3 &pos, float sz); + +void Renderer::render(const Level *lvl) const +{ + Volume *vol = lvl->terrain; + + glEnable(GL_COLOR_MATERIAL); + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + + glBegin(GL_QUADS); + for(int i=0; iget_size(0); i++) { + for(int j=0; jget_size(1); j++) { + for(int k=0; kget_size(2) - 1; k++) { + Vector4 vox = vol->get_voxel(i, j, k); + Vector4 next = vol->get_voxel(i, j, k + 1); + + if(vox.w > 0.1 && next.w < 0.1) { + glColor3f(vox.x, vox.y, vox.z); + + float x = ((float)i - vol->get_size(0) / 2) * 0.1; + float z = ((float)j - vol->get_size(1) / 2) * 0.1; + float y = ((float)k - vol->get_size(2) / 2) * 0.1; + draw_cube(Vector3(x, y, z), 0.1); + } + } + } + } + glEnd(); + + glDisable(GL_COLOR_MATERIAL); +} + + +static void draw_cube(const Vector3 &pos, float sz) +{ + sz /= 2.0; + + glNormal3f(0, 0, 1); + glVertex3f(pos.x - sz, pos.y - sz, pos.z + sz); + glVertex3f(pos.x + sz, pos.y - sz, pos.z + sz); + glVertex3f(pos.x + sz, pos.y + sz, pos.z + sz); + glVertex3f(pos.x - sz, pos.y + sz, pos.z + sz); + + glNormal3f(1, 0, 0); + glVertex3f(pos.x + sz, pos.y - sz, pos.z + sz); + glVertex3f(pos.x + sz, pos.y - sz, pos.z - sz); + glVertex3f(pos.x + sz, pos.y + sz, pos.z - sz); + glVertex3f(pos.x + sz, pos.y + sz, pos.z + sz); + + glNormal3f(0, 0, -1); + glVertex3f(pos.x + sz, pos.y - sz, pos.z - sz); + glVertex3f(pos.x - sz, pos.y - sz, pos.z - sz); + glVertex3f(pos.x - sz, pos.y + sz, pos.z - sz); + glVertex3f(pos.x + sz, pos.y + sz, pos.z - sz); + + glNormal3f(-1, 0, 0); + glVertex3f(pos.x - sz, pos.y - sz, pos.z - sz); + glVertex3f(pos.x - sz, pos.y - sz, pos.z + sz); + glVertex3f(pos.x - sz, pos.y + sz, pos.z + sz); + glVertex3f(pos.x - sz, pos.y + sz, pos.z - sz); + + glNormal3f(0, 1, 0); + glVertex3f(pos.x - sz, pos.y + sz, pos.z + sz); + glVertex3f(pos.x + sz, pos.y + sz, pos.z + sz); + glVertex3f(pos.x + sz, pos.y + sz, pos.z - sz); + glVertex3f(pos.x - sz, pos.y + sz, pos.z - sz); + + glNormal3f(0, -1, 0); + glVertex3f(pos.x - sz, pos.y - sz, pos.z - sz); + glVertex3f(pos.x + sz, pos.y - sz, pos.z - sz); + glVertex3f(pos.x + sz, pos.y - sz, pos.z + sz); + glVertex3f(pos.x - sz, pos.y - sz, pos.z + sz); + +} diff -r e4818a3300b9 -r cfe68befb7cc src/renderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/renderer.h Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,23 @@ +#ifndef RENDERER_H_ +#define RENDERER_H_ + +#include "shaders.h" +#include "texture.h" +#include "level.h" + +class Renderer { +private: + mutable Texture3D *leveltex; + SdrProg *sdrprog; + +public: + Renderer(); + ~Renderer(); + + bool init(); + void shutdown(); + + void render(const Level *lvl) const; +}; + +#endif // RENDERER_H_ diff -r e4818a3300b9 -r cfe68befb7cc src/shaders.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shaders.cc Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,297 @@ +#include +#include +#include +#ifdef _MSC_VER +#include +#else +#include +#endif +#include +#include "shaders.h" + +Shader::Shader(unsigned int type) +{ + sdr = glCreateShader(type); + compiled = false; + + assert(glGetError() == GL_NO_ERROR); +} + +Shader::~Shader() +{ + glDeleteShader(sdr); +} + +void Shader::set_source(const char *src) +{ + glShaderSource(sdr, 1, &src, 0); + compiled = false; + + assert(glGetError() == GL_NO_ERROR); +} + +bool Shader::compile() +{ + if(compiled) { + return true; + } + + glCompileShader(sdr); + + int len; + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &len); + if(len) { + char *buf = (char*)alloca(len + 1); + glGetShaderInfoLog(sdr, len, &len, buf); + fprintf(stderr, "compiler: %s\n", buf); + } + + int status; + glGetShaderiv(sdr, GL_COMPILE_STATUS, &status); + if(!status) { + fprintf(stderr, "shader compilation failed\n"); + return false; + } + + compiled = true; + return true; +} + +bool Shader::is_compiled() const +{ + return compiled; +} + +bool Shader::load(const char *fname) +{ + FILE *fp; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "failed to open shader file: %s\n", fname); + return false; + } + + fseek(fp, 0, SEEK_END); + long sz = ftell(fp); + rewind(fp); + + char *buf = new char[sz + 1]; + if((long)fread(buf, 1, sz, fp) < sz) { + fprintf(stderr, "failed to read shader contents\n"); + fclose(fp); + return false; + } + fclose(fp); + + set_source(buf); + delete [] buf; + + return compile(); +} + +// ---- shader manager ---- +static std::map sdrcache; + +Shader *get_shader(const char *fname, unsigned int type) +{ + std::map::const_iterator it; + + if((it = sdrcache.find(std::string(fname))) != sdrcache.end()) { + return it->second; + } + + Shader *sdr = new Shader(type); + if(!sdr->load(fname)) { + delete sdr; + return 0; + } + sdrcache[fname] = sdr; + return sdr; +} + + +// ---- class SdrProg ---- + +SdrProg::SdrProg() +{ + prog = glCreateProgram(); + linked = false; + assert(glGetError() == GL_NO_ERROR); +} + +SdrProg::~SdrProg() +{ + glDeleteProgram(prog); +} + +void SdrProg::add_shader(Shader *sdr) +{ + if(sdr->compile()) { + glAttachShader(prog, sdr->sdr); + assert(glGetError() == GL_NO_ERROR); + + shaders.push_back(sdr); + linked = false; + } +} + +bool SdrProg::link() +{ + if(linked) { + return true; + } + + glLinkProgram(prog); + + int len; + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len); + if(len) { + char *buf = (char*)alloca(len + 1); + glGetProgramInfoLog(prog, len, &len, buf); + assert(glGetError() == GL_NO_ERROR); + fprintf(stderr, "linker: %s\n", buf); + } + + int status; + glGetProgramiv(prog, GL_LINK_STATUS, &status); + if(!status) { + fprintf(stderr, "program linking failed\n"); + return false; + } + + linked = true; + return true; +} + +bool SdrProg::load(const char *vsfname, const char *psfname) +{ + Shader *sdr; + + if(vsfname) { + if(!(sdr = get_shader(vsfname, GL_VERTEX_SHADER))) { + return false; + } + add_shader(sdr); + } + + if(psfname) { + if(!(sdr = get_shader(psfname, GL_FRAGMENT_SHADER))) { + return false; + } + add_shader(sdr); + } + return link(); +} + +int SdrProg::get_uniform_location(const char *name) +{ + bind_program(this); + return glGetUniformLocation(prog, name); +} + +int SdrProg::get_attribute_location(const char *name) +{ + bind_program(this); + return glGetAttribLocation(prog, name); +} + +void SdrProg::set_uniform(const char *name, int val) +{ + set_uniform(get_uniform_location(name), val); +} + +void SdrProg::set_uniform(const char *name, float val) +{ + set_uniform(get_uniform_location(name), val); +} + +void SdrProg::set_uniform(const char *name, const Vector2 &v) +{ + set_uniform(get_uniform_location(name), v); +} + +void SdrProg::set_uniform(const char *name, const Vector3 &v) +{ + set_uniform(get_uniform_location(name), v); +} + +void SdrProg::set_uniform(const char *name, const Vector4 &v) +{ + set_uniform(get_uniform_location(name), v); +} + +void SdrProg::set_uniform(const char *name, const Matrix4x4 &mat) +{ + set_uniform(get_uniform_location(name), mat); +} + + +void SdrProg::set_uniform(int loc, int val) +{ + if(loc >= 0) { + bind_program(this); + glUniform1i(loc, val); + } +} + +void SdrProg::set_uniform(int loc, float val) +{ + if(loc >= 0) { + bind_program(this); + glUniform1f(loc, val); + } +} + +void SdrProg::set_uniform(int loc, const Vector2 &v) +{ + if(loc >= 0) { + bind_program(this); + glUniform2f(loc, v.x, v.y); + } +} + +void SdrProg::set_uniform(int loc, const Vector3 &v) +{ + if(loc >= 0) { + bind_program(this); + glUniform3f(loc, v.x, v.y, v.z); + } +} + +void SdrProg::set_uniform(int loc, const Vector4 &v) +{ + if(loc >= 0) { + bind_program(this); + glUniform4f(loc, v.x, v.y, v.z, v.w); + } +} + +void SdrProg::set_uniform(int loc, const Matrix4x4 &mat) +{ + if(loc >= 0) { + bind_program(this); + // loading transpose matrix (3rd arg true) +#ifdef SINGLE_PRECISION_MATH + glUniformMatrix4fv(loc, 1, GL_TRUE, (float*)mat.m); +#else + glUniformMatrix4dv(loc, 1, GL_TRUE, (double*)mat.m); +#endif + } +} + +bool bind_program(const SdrProg *prog) +{ + if(!prog) { + glUseProgram(0); + return true; + } + + if(!((SdrProg*)prog)->link()) { + return false; + } + glUseProgram(prog->prog); + if(glGetError()) { + return false; + } + return true; +} diff -r e4818a3300b9 -r cfe68befb7cc src/shaders.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shaders.h Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,67 @@ +#ifndef SDR_H_ +#define SDR_H_ + +#include +#include "vmath/vmath.h" + +class Shader { +private: + bool compiled; + +public: + unsigned int sdr; + + Shader(unsigned int type); + ~Shader(); + + void set_source(const char *src); + + bool compile(); + bool is_compiled() const; + + bool load(const char *fname); +}; + + +// public shader manager interface +Shader *get_shader(const char *fname, unsigned int type); + + +class SdrProg { +private: + // SdrProg does not own the shader objects + std::vector shaders; + bool linked; + +public: + unsigned int prog; + + SdrProg(); + ~SdrProg(); + + void add_shader(Shader *sdr); + bool link(); + + bool load(const char *vsfname, const char *psfname); + + int get_uniform_location(const char *name); + int get_attribute_location(const char *name); + + void set_uniform(const char *name, int val); + void set_uniform(const char *name, float val); + void set_uniform(const char *name, const Vector2 &v); + void set_uniform(const char *name, const Vector3 &v); + void set_uniform(const char *name, const Vector4 &v); + void set_uniform(const char *name, const Matrix4x4 &mat); + + void set_uniform(int loc, int val); + void set_uniform(int loc, float val); + void set_uniform(int loc, const Vector2 &v); + void set_uniform(int loc, const Vector3 &v); + void set_uniform(int loc, const Vector4 &v); + void set_uniform(int loc, const Matrix4x4 &mat); +}; + +bool bind_program(const SdrProg *prog); + +#endif /* SDR_H_ */ diff -r e4818a3300b9 -r cfe68befb7cc src/texture.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/texture.cc Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,81 @@ +#include "opengl.h" +#include "texture.h" + +void bind_texture(const Texture *tex, int texunit) +{ + static const Texture *curr_tex[8]; + + if(tex == curr_tex[texunit]) { + return; + } + + glActiveTexture(GL_TEXTURE0 + texunit); + if(tex) { + glEnable(tex->type); + glBindTexture(tex->type, tex->tex); + } else { + glDisable(tex->type); + } + glActiveTexture(GL_TEXTURE0); + + curr_tex[texunit] = tex; +} + + +Texture::Texture() +{ + type = 0; + + size[0] = size[1] = size[2] = 0; + + glGenTextures(1, &tex); +} + +Texture::~Texture() +{ + if(tex) { + glDeleteTextures(1, &tex); + } +} + +int Texture::get_size(int idx) const +{ + return idx >= 0 && idx < 3 ? size[idx] : 0; +} + +Texture2D::Texture2D() +{ + type = GL_TEXTURE_2D; + + glBindTexture(type, tex); + glTexParameteri(type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +} + +void Texture2D::create(int xsz, int ysz, float *data) +{ + glBindTexture(type, tex); + glTexImage2D(type, 0, GL_RGBA, xsz, ysz, 0, GL_RGBA, GL_FLOAT, data); + + size[0] = xsz; + size[1] = ysz; +} + +Texture3D::Texture3D() +{ + type = GL_TEXTURE_3D; + + glBindTexture(type, tex); + glTexParameteri(type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +} + +void Texture3D::create(int xsz, int ysz, int zsz, float *data) +{ + glBindTexture(type, tex); + glTexImage3D(type, 0, GL_RGBA, xsz, ysz, zsz, 0, GL_RGBA, GL_FLOAT, data); + + size[0] = xsz; + size[1] = ysz; + size[2] = zsz; +} diff -r e4818a3300b9 -r cfe68befb7cc src/texture.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/texture.h Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,36 @@ +#ifndef TEXTURE_H_ +#define TEXTURE_H_ + +class Texture { +protected: + unsigned int type; + unsigned int tex; + + int size[3]; + +public: + Texture(); + virtual ~Texture(); + + virtual int get_size(int idx) const; + + friend void bind_texture(const Texture *tex, int texunit); +}; + +void bind_texture(const Texture *tex, int texunit = 0); + +class Texture2D : public Texture { +public: + Texture2D(); + + void create(int xsz, int ysz, float *data = 0); +}; + +class Texture3D : public Texture { +public: + Texture3D(); + + void create(int xsz, int ysz, int zsz, float *data = 0); +}; + +#endif // TEXTURE_H_ diff -r e4818a3300b9 -r cfe68befb7cc src/volume.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/volume.h Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,39 @@ +#ifndef VOLUME_H_ +#define VOLUME_H_ + +#include "vmath/vmath.h" + +class Volume { +private: + int xsz, ysz, zsz; + int slice_size; + Vector4 *voxels; + + Vector4 **slices; + +public: + inline Volume(int xsz, int ysz, int zsz); + inline ~Volume(); + + inline int get_size(int idx = -1) const; + + // access to the voxel data based on voxel coordinates + inline void set_voxel(int x, int y, int z, const Vector4 &val); + inline void set_voxel_color(int x, int y, int z, const Vector3 &col); + inline void set_voxel_alpha(int x, int y, int z, float alpha); + + inline const Vector4 &get_voxel(int x, int y, int z) const; + inline const Vector3 get_voxel_color(int x, int y, int z) const; + inline float get_voxel_alpha(int x, int y, int z) const; + + // linear access to the voxel data + inline Vector4 &operator [](int idx); + inline const Vector4 &operator [](int idx) const; + + // raw access to the voxel data for building the OpenGL texture directly + inline const Vector4 *get_data_ptr() const; +}; + +#include "volume.inl" + +#endif // VOLUME_H_ diff -r e4818a3300b9 -r cfe68befb7cc src/volume.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/volume.inl Sat Dec 15 23:43:03 2012 +0200 @@ -0,0 +1,88 @@ +Volume::Volume(int xsz, int ysz, int zsz) +{ + this->xsz = xsz; + this->ysz = ysz; + this->zsz = zsz; + slice_size = xsz * ysz; + + voxels = new Vector4[xsz * ysz * zsz]; + + // precalculate slice start pointers, cause why not... + slices = new Vector4*[zsz]; + for(int i=0; ix = col.x; + ptr->y = col.y; + ptr->z = col.z; +} + +void Volume::set_voxel_alpha(int x, int y, int z, float alpha) +{ + slices[z][y * xsz + x].w = alpha; +} + + +const Vector4 &Volume::get_voxel(int x, int y, int z) const +{ + return slices[z][y * xsz + x]; +} + +const Vector3 Volume::get_voxel_color(int x, int y, int z) const +{ + Vector4 *ptr = slices[z] + y * xsz + x; + return Vector3(ptr->x, ptr->y, ptr->z); +} + +float Volume::get_voxel_alpha(int x, int y, int z) const +{ + return slices[z][y * xsz + x].w; +} + + +Vector4 &Volume::operator [](int idx) +{ + return voxels[idx]; +} + +const Vector4 &Volume::operator [](int idx) const +{ + return voxels[idx]; +} + + +const Vector4 *Volume::get_data_ptr() const +{ + return voxels; +} +