/**
 * Called every time the cursor moves. It is used to calculate the Camera's direction
 * in window - the window holding the cursor
 * in xpos   - the xposition of the cursor on the screen
 * in ypos   - the yposition of the curose on the screen
 */
static void cursor_position_callback(GLFWwindow *window, double xpos, double ypos) {

    GLfloat quat[] = {0.0f,0.0f,0.0f,0.0f};

    //calculate pitch
    static double  previous_ypos = ypos;
    double position_y_difference = ypos - previous_ypos;
    previous_ypos = ypos;

    //calculate yaw
    static double previous_xpos = xpos;
    double position_x_difference = xpos - previous_xpos;
    previous_xpos = xpos;

    //reduce signal
    camera.yaw += position_x_difference *camera.signal_amplifier;
    camera.pitch += position_y_difference *camera.signal_amplifier;

    //calculate rotation sequence
    create_versor(quat, camera.pitch, 1.0f, 0.0f, 0.0f);
    quat_to_mat4(camera.Rpitch.m, quat);
    create_versor(quat, camera.yaw, 0.0f, 1.0f, 0.0f);
    quat_to_mat4(camera.Ryaw.m,quat);

//    mult_quat_quat(camera.resultQuat, camera.quatYaw, camera.quatPitch);
//    mult_quat_quat(camera.resultQuat, camera.quatYaw, camera.quatPitch);
//    quat_to_mat4(camera.R.m, camera.resultQuat);

}
static void calculateCursorRotations(Cursor *cursor){
    GLfloat quat[] = {0.0f,0.0f,0.0f,0.0f};
    create_versor(quat, cursor->pitch, 1.0f, 0.0f, 0.0f);
    quat_to_mat4(cursor->Rpitch.m, quat);
    create_versor(quat, cursor->yaw, 0.0f, 1.0f, 0.0f);
    quat_to_mat4(cursor->Ryaw.m, quat);
    create_versor(quat, cursor->roll, 0.0f, 0.0f, 1.0f);
    quat_to_mat4(cursor->Rroll.m, quat);
}
Exemple #3
0
/* Sync rigid body and object transformations */
void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
{
	RigidBodyOb *rbo = ob->rigidbody_object;

	/* keep original transform for kinematic and passive objects */
	if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE)
		return;

	/* use rigid body transform after cache start frame if objects is not being transformed */
	if (BKE_rigidbody_check_sim_running(rbw, ctime) && !(ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
		float mat[4][4], size_mat[4][4], size[3];

		normalize_qt(rbo->orn); // RB_TODO investigate why quaternion isn't normalized at this point
		quat_to_mat4(mat, rbo->orn);
		copy_v3_v3(mat[3], rbo->pos);

		mat4_to_size(size, ob->obmat);
		size_to_mat4(size_mat, size);
		mul_m4_m4m4(mat, mat, size_mat);

		copy_m4_m4(ob->obmat, mat);
	}
	/* otherwise set rigid body transform to current obmat */
	else {
		mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
	}
}
Exemple #4
0
GLCamera::GLCamera(float aspect)
{
	near = 0.1f; 
	far = 100.0f; 
	fovy = 67.0f; 
	//aspect = (float)g_gl_width / (float)g_gl_height;
	this->aspect = aspect;
	proj_mat = perspective(fovy, this->aspect, near, far);

	cam_speed = 5.0f; 
	cam_heading_speed = 100.0f;

	cam_heading = 0.0f; 
	cam_pos = vector3(0.0f, 0.0f, 5.0f);
	T = identity_mat4().translate( vector3(-cam_pos.v[0], -cam_pos.v[1], -cam_pos.v[2]) );

	create_versor(quaternion, -cam_heading, 0.0f, 1.0f, 0.0f);
	quat_to_mat4(R.m, quaternion);
	// combine the inverse rotation and transformation to make a view matrix
	view_mat = R * T;

	// keep track of some useful vectors that can be used for keyboard movement
	fwd = vector4(0.0f, 0.0f, -1.0f, 0.0f);
	rgt = vector4(1.0f, 0.0f, 0.0f, 0.0f);
	up = vector4(0.0f, 1.0f, 0.0f, 0.0f);

	cam_yaw = 0.0f; // y-rotation in degrees
	cam_pitch = 0.0f;
	cam_roll = 0.0;
}
Exemple #5
0
Camera::Camera(int view_mat_location, int proj_mat_location) {
	this->view_mat_location = view_mat_location;
	this->proj_mat_location = proj_mat_location;
	cam_pos = vec3 (0.0f, 0.0f, 5.0f);
	near = 0.1f; // clipping plane
	far = 100.0f; // clipping plane
	fovy = 67.0f; // 67 degrees
	// aspect ratio
	aspect = (float)g_gl_width / (float)g_gl_height;
	proj_mat = perspective (fovy, aspect, near, far);
	cam_speed = 5.0f; // 1 unit per second
	cam_heading_speed = 100.0f; // 30 degrees per second
	cam_heading = 0.0f; // y-rotation in degrees
	T = translate (
		identity_mat4 (), vec3 (-cam_pos.v[0], -cam_pos.v[1], -cam_pos.v[2])
	);
	create_versor (quaternion, -cam_heading, 0.0f, 1.0f, 0.0f);
	// convert the quaternion to a rotation matrix (just an array of 16 floats)
	quat_to_mat4 (R.m, quaternion);
	// combine the inverse rotation and transformation to make a view matrix
	view_mat = R * T;

	fwd = FORWARD;
	rgt = RIGHT;
	up = UP;

	set_view();
	set_proj();

	reset_control();
}
void skyUpdate(Skybox *sky){

    //calculate new sky ngle
    GLfloat quat[] = {0.0f,0.0f,0.0f,0.0f};
    sky->angle += 0.002f;
    if (sky->angle> 359) sky->angle= 0;
    create_versor(quat, sky->angle, 0.0f, 1.0f, 0.0f);
    quat_to_mat4(sky->modelMatrix.m, quat);
}
Exemple #7
0
/* don't set windows active in here, is used by renderwin too */
void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
{
	if (rv3d->persp == RV3D_CAMOB) {      /* obs/camera */
		if (v3d->camera) {
			BKE_object_where_is_calc(scene, v3d->camera);
			obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
		}
		else {
			quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
			rv3d->viewmat[3][2] -= rv3d->dist;
		}
	}
	else {
		/* should be moved to better initialize later on XXX */
		if (rv3d->viewlock)
			ED_view3d_lock(rv3d);
		
		quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
		if (rv3d->persp == RV3D_PERSP) rv3d->viewmat[3][2] -= rv3d->dist;
		if (v3d->ob_centre) {
			Object *ob = v3d->ob_centre;
			float vec[3];
			
			copy_v3_v3(vec, ob->obmat[3]);
			if (ob->type == OB_ARMATURE && v3d->ob_centre_bone[0]) {
				bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, v3d->ob_centre_bone);
				if (pchan) {
					copy_v3_v3(vec, pchan->pose_mat[3]);
					mul_m4_v3(ob->obmat, vec);
				}
			}
			translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
		}
		else if (v3d->ob_centre_cursor) {
			float vec[3];
			copy_v3_v3(vec, give_cursor(scene, v3d));
			translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
		}
		else {
			translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
		}
	}
}
Exemple #8
0
void GLCamera::movePitchDown(double elapsed_seconds)
{
	cam_pitch -= cam_heading_speed * elapsed_seconds;
	float q_pitch[16];
	create_versor(q_pitch, cam_pitch, rgt.v[0], rgt.v[1], rgt.v[2]);
	mult_quat_quat(quaternion, q_pitch, quaternion);

	// recalc axes to suit new orientation
	quat_to_mat4(R.m, quaternion);
	fwd = R * vector4(0.0, 0.0, -1.0, 0.0);
	rgt = R * vector4(1.0, 0.0, 0.0, 0.0);
	up = R * vector4(0.0, 1.0, 0.0, 0.0);
}
Exemple #9
0
void GLCamera::rollRight(double elapsed_seconds)
{
	cam_roll += cam_heading_speed * elapsed_seconds;
	float q_roll[16];
	create_versor(q_roll, cam_roll, fwd.v[0], fwd.v[1], fwd.v[2]);
	mult_quat_quat(quaternion, q_roll, quaternion);

	// recalc axes to suit new orientation
	quat_to_mat4(R.m, quaternion);
	fwd = R * vector4(0.0, 0.0, -1.0, 0.0);
	rgt = R * vector4(1.0, 0.0, 0.0, 0.0);
	up = R * vector4(0.0, 1.0, 0.0, 0.0);

}
Exemple #10
0
void display_render_io_process(struct s_vm* vm, t_display* display)
{
	t_v4	color_io_process;
	t_v4	color_ambient;
	t_v3	light_direction;
	t_mat4	local;
	t_mat4	translate;
	t_mat4	rotation;
	t_quat	quat;
	int		i;

	v4_set(&color_io_process, 0.4f, 0.4f, 1.0f, 0.0f);
	v4_set(&color_ambient, 0.2f, 0.2f, 0.2f, 1.0f);
	v3_set(&light_direction, 0, 0, -1.0f);


	display_mesh_render_start(display->mesh_renderer, MESH_TYPE_VN);
	display_mesh_set_ambient(display->mesh_renderer, &color_ambient);
	display_mesh_set_light_direction(display->mesh_renderer, &light_direction);
	display_mesh_set_diffuse(display->mesh_renderer, &color_io_process);
	display_mesh_set_projection(display->mesh_renderer, &display->projection_view);
	mat4_ident(&local);

	for (i = 0; i < vm->process_count; ++i)
	{
		t_process* process = vm->processes[i];
		float angle = (float)process->cycle_create + (float)display->frame_last_time ;

		int index = process->pc;
		float x = (float) (index % display->memory_stride);
		float y = (float) (index / display->memory_stride);

		x = x * DISPLAY_CELL_SIZE + DISPLAY_CELL_SIZE * 0.5f;
		y = y * DISPLAY_CELL_SIZE + DISPLAY_CELL_SIZE * 0.5f;

		mat4_ident(&translate);
		mat4_translate(&translate, x, y, DISPLAY_CELL_SIZE * 0.5f);

		quat_from_euler(&quat, angle, angle, angle);
		quat_to_mat4(&quat, &rotation);

		mat4_mul(&translate, &rotation, &local);

		display_mesh_set_local(display->mesh_renderer, &local);

		display_mesh_render(display->process_mesh);
	}
}
Exemple #11
0
void GLCamera::moveYawLeft(double elapsed_seconds)
{
	cam_yaw += getHeadingSpeed() * elapsed_seconds;

	// create a quaternion representing change in heading (the yaw)
	float q_yaw[16];
	create_versor(q_yaw, cam_yaw, up.v[0], up.v[1], up.v[2]);
	// add yaw rotation to the camera's current orientation
	mult_quat_quat(quaternion, q_yaw, quaternion);

	// recalc axes to suit new orientation
	quat_to_mat4(R.m, quaternion);
	fwd = R * vector4(0.0, 0.0, -1.0, 0.0);
	rgt = R * vector4(1.0, 0.0, 0.0, 0.0);
	up  = R * vector4(0.0, 1.0, 0.0, 0.0);

}
Exemple #12
0
void Camera::update() {

	// update view matrix
	if (cam_moved) {
		quat_to_mat4 (R.m, quaternion);

		// checking for fp errors
		//	printf ("dot fwd . up %f\n", dot (fwd, up));
		//	printf ("dot rgt . up %f\n", dot (rgt, up));
		//	printf ("dot fwd . rgt\n %f", dot (fwd, rgt));

		cam_pos += vec3 (fwd) * -move.v[2];
		cam_pos += vec3 (up) * move.v[1];
		cam_pos += vec3 (rgt) * move.v[0];
		T = translate (identity_mat4 (), vec3 (cam_pos));

		view_mat = inverse (R) * inverse (T);
		set_view();
	}
}
Exemple #13
0
void GLCamera::setPosition(vector3 pos)
{ 
	this->cam_pos = pos; 
	T = identity_mat4().translate(vector3(-cam_pos.v[0], -cam_pos.v[1], -cam_pos.v[2]));
	T = identity_mat4().translate( vector3(-cam_pos.v[0], -cam_pos.v[1], -cam_pos.v[2]) );

	create_versor(quaternion, -cam_heading, 0.0f, 1.0f, 0.0f);
	quat_to_mat4(R.m, quaternion);
	// combine the inverse rotation and transformation to make a view matrix
	view_mat = R * T;

	// keep track of some useful vectors that can be used for keyboard movement
	fwd = vector4(0.0f, 0.0f, -1.0f, 0.0f);
	rgt = vector4(1.0f, 0.0f, 0.0f, 0.0f);
	up = vector4(0.0f, 1.0f, 0.0f, 0.0f);

	cam_yaw = 0.0f; // y-rotation in degrees
	cam_pitch = 0.0f;
	cam_roll = 0.0;

}
Exemple #14
0
void GLCamera::updatePosition(vector3 move)
{
	quat_to_mat4(R.m, quaternion);

	// checking for fp errors
	//	printf ("dot fwd . up %f\n", dot (fwd, up));
	//	printf ("dot rgt . up %f\n", dot (rgt, up));
	//	printf ("dot fwd . rgt\n %f", dot (fwd, rgt));

	cam_pos = cam_pos + vector3(fwd) * -move.v[2];
	cam_pos = cam_pos + vector3(up) * move.v[1];
	cam_pos = cam_pos + vector3(rgt) * move.v[0];
	matriz4x4 T = identity_mat4().translate(vector3(cam_pos));

	view_mat = R.inverse() * T.inverse();

	cam_yaw = 0.0f;
	cam_pitch = 0.0f;
	cam_roll = 0.0;

}
Exemple #15
0
void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
{
    int i;
    mat4_t rmat;
    vec3_t pos, scale;
    quat_t rot;

    pos = anm_get_node_position(node, tm);
    rot = anm_get_node_rotation(node, tm);
    scale = anm_get_node_scaling(node, tm);

    m4_set_translation(mat, node->pivot.x, node->pivot.y, node->pivot.z);

    quat_to_mat4(rmat, rot);
    for(i=0; i<3; i++) {
        mat[i][0] = rmat[i][0];
        mat[i][1] = rmat[i][1];
        mat[i][2] = rmat[i][2];
    }
    /* this loop is equivalent to: m4_mult(mat, mat, rmat); */

    mat[0][0] *= scale.x;
    mat[0][1] *= scale.y;
    mat[0][2] *= scale.z;
    mat[0][3] += pos.x;
    mat[1][0] *= scale.x;
    mat[1][1] *= scale.y;
    mat[1][2] *= scale.z;
    mat[1][3] += pos.y;
    mat[2][0] *= scale.x;
    mat[2][1] *= scale.y;
    mat[2][2] *= scale.z;
    mat[2][3] += pos.z;

    m4_translate(mat, -node->pivot.x, -node->pivot.y, -node->pivot.z);

    /* that's basically: pivot * rotation * translation * scaling * -pivot */
}
Exemple #16
0
int main () {
    // start GL context and O/S window using the GLFW helper library
    if (!glfwInit ()) {
        fprintf (stderr, "ERROR: could not start GLFW3\n");
        return 1;
    }
    
    // uncomment these lines if on Apple OS X
    glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
    GLFWwindow* window = glfwCreateWindow (640, 480, "Cube to Sphere", NULL, NULL);
    if (!window) {
        fprintf (stderr, "ERROR: could not open window with GLFW3\n");
        glfwTerminate();
        return 1;
    }
    GLFWwindow* window2 = glfwCreateWindow (640, 480, "Just checking", NULL, NULL);
    if (!window2) {
        fprintf (stderr, "ERROR: could not open window with GLFW3\n");
        glfwTerminate();
        return 1;
    }
    glfwMakeContextCurrent (window);
    
    //start GLEW extension handler
    glewExperimental = GL_TRUE;
    glewInit ();
    
    // get version info
    const GLubyte* renderer = glGetString (GL_RENDERER); // get renderer string
    const GLubyte* version = glGetString (GL_VERSION); // version as a string
    printf ("Renderer: %s\n", renderer);
    printf ("OpenGL version supported %s\n", version);
    //CLGLUtils::init();
    boost::compute::context context;
    try {
        context = boost::compute::opengl_create_shared_context();
        
    } catch (std::exception e) {
        std::cerr<<"Failed to initialize a CLGL context"<<e.what()<<std::endl;
        exit(0);
    }
    
    // tell GL to only draw onto a pixel if the shape is closer to the viewer
    glEnable (GL_DEPTH_TEST); // enable depth-testing
    glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
    
    // OTHER STUFF GOES HERE NEXT
    float points[] = {
        -1.0f,  1.0f, -1.0f,
        -1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f, -1.0f,
        
        -1.0f, -1.0f,  1.0f,
        -1.0f, -1.0f, -1.0f,
        -1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f,
        
        1.0f, -1.0f, -1.0f,
        1.0f, -1.0f,  1.0f,
        1.0f,  1.0f,  1.0f,
        1.0f,  1.0f,  1.0f,
        1.0f,  1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        
        -1.0f, -1.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,
        1.0f,  1.0f,  1.0f,
        1.0f,  1.0f,  1.0f,
        1.0f, -1.0f,  1.0f,
        -1.0f, -1.0f,  1.0f,
        
        -1.0f,  1.0f, -1.0f,
        1.0f,  1.0f, -1.0f,
        1.0f,  1.0f,  1.0f,
        1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f,  1.0f,
        -1.0f,  1.0f, -1.0f,
        
        -1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f,  1.0f,
        1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        -1.0f, -1.0f,  1.0f,
        1.0f, -1.0f,  1.0f
    };
    
    
    GLuint vbo;
    glGenBuffers (1, &vbo);
    glBindBuffer (GL_ARRAY_BUFFER, vbo);
    glBufferData (GL_ARRAY_BUFFER, 3 * 36 * sizeof (float), &points, GL_STATIC_DRAW);
    
    
    GLuint vao;
    glGenVertexArrays (1, &vao);
    glBindVertexArray (vao);
    glEnableVertexAttribArray (0);
    glBindBuffer (GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);



    //Create Cube map
    GLuint cube_map_texture;
    
    create_cube_map ((resource_dir+"negz.jpg").c_str(), (resource_dir+"posz.jpg").c_str(), (resource_dir+"posy.jpg").c_str(), (resource_dir+"negy.jpg").c_str(), (resource_dir+"negx.jpg").c_str(), (resource_dir+"posx.jpg").c_str(), &cube_map_texture);
    boost::shared_ptr<boost::compute::opengl_texture> cl_cube_map_texture;
    try {
        cl_cube_map_texture = boost::shared_ptr<boost::compute::opengl_texture>(new boost::compute::opengl_texture(context,GL_TEXTURE_2D_ARRAY,0,cube_map_texture,boost::compute::memory_object::mem_flags::read_only));
    } catch ( const std::exception& e ) {
        std::cerr << e.what() << std::endl;
    }
    
    const char* vertex_shader =
    "#version 400\n"
    "in vec3 vp;"
    "uniform mat4 P, V;"
   // "uniform vec3 vertOut;"
    "out vec3 texcoords;"
    "vec3 newP;"
    "void main () {"
    "    texcoords = vp;"
   // "    vertOut = vp;"
    "    gl_Position = P * V * vec4 (vp, 1.0);"
    "}";
    
    const char* fragment_shader = loadShader(resource_dir+"fragmentShader.frag").c_str();

    
    /*"#version 400\n"
    "in vec3 texcoords;"
    "uniform samplerCube cube_texture;"
    "out vec4 frag_colour;"
    "vec4 cubeToLatLon(samplerCube cubemap, vec3 inUV) {"
    "vec3 cubmapTexCoords;"
    //"cubmapTexCoords.x = inUV.x*sqrt(1 - ( (inUV.y * inUV.y)/2 ) - ( (inUV.z * inUV.z)/2 ) + ( ( (inUV.y * inUV.y) * (inUV.z * inUV.z))/3));"
    "cubmapTexCoords.x = inUV.x;"
    //"cubmapTexCoords.y= inUV.y*sqrt(1 - ( (inUV.z * inUV.z)/2 ) - ( (inUV.x * inUV.x)/2 ) + ( ( (inUV.z * inUV.z) * (inUV.x * inUV.x))/3));"
    "cubmapTexCoords.y = inUV.y;"
    "cubmapTexCoords.z = inUV.z*sqrt(1 - ( (inUV.x * inUV.x)/2 ) - ( (inUV.y * inUV.y)/2 ) + ( ( (inUV.x * inUV.x) * (inUV.y * inUV.y))/3));"
    //"cubmapTexCoords.z = inUV.z;"
    "return texture(cubemap, cubmapTexCoords);"
    "}"
    "void main () {"
    //"  frag_colour = texture (cube_texture, texcoords);"
    "  frag_colour = cubeToLatLon (cube_texture, texcoords);"
    "}";*/
    
    
    GLuint vs = glCreateShader (GL_VERTEX_SHADER);
    glShaderSource (vs, 1, &vertex_shader, NULL);
    glCompileShader (vs);
    GLuint fs = glCreateShader (GL_FRAGMENT_SHADER);
    glShaderSource (fs, 1, &fragment_shader, NULL);
    glCompileShader (fs);
    
    
    GLuint cube_sp = glCreateProgram ();
    glAttachShader (cube_sp, fs);
    glAttachShader (cube_sp, vs);
    glLinkProgram (cube_sp);
    
    //*-----------------------------Compile Shaders for second window - square --------*/
    
    glfwMakeContextCurrent(window2);
    
    //start GLEW extension handler
    glewExperimental = GL_TRUE;
    glewInit ();
    glEnable (GL_DEPTH_TEST); // enable depth-testing
    glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
    
    float squarePoints[] =
    {
        -1.0f,  1.0f, -1.0f,
        -1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        1.0f, -1.0f, -1.0f,
        1.0f,  1.0f, -1.0f,
        -1.0f,  1.0f, -1.0f
    };
    
    GLfloat texcoords[] = {
        0.0f, 0.0f,
        1.0f, 0.0f,
        1.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 1.0f,
        0.0f, 0.0f
    };
    
    GLuint vbo_square;
    glGenBuffers (1, &vbo_square);
    glBindBuffer (GL_ARRAY_BUFFER, vbo_square);
    glBufferData (GL_ARRAY_BUFFER, 3 * 6 * sizeof (float), &squarePoints, GL_STATIC_DRAW);
    
    GLuint texcoords_vbo;
    glGenBuffers (1, &texcoords_vbo);
    glBindBuffer (GL_ARRAY_BUFFER, texcoords_vbo);
    glBufferData (GL_ARRAY_BUFFER, 12 * sizeof (GLfloat), texcoords, GL_STATIC_DRAW);
    
    GLuint vao_square;
    glGenVertexArrays (1, &vao_square);
    glBindVertexArray (vao_square);
    glBindBuffer (GL_ARRAY_BUFFER, vbo_square);
    glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
    glBindBuffer (GL_ARRAY_BUFFER, texcoords_vbo);
    glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, NULL); // normalise!
    glEnableVertexAttribArray (0);
    glEnableVertexAttribArray (1);
    
   

    GLuint square_sp = create_programme_from_files((resource_dir+"square.vert").c_str(), (resource_dir+"square.frag").c_str());
    
    GLuint tex;
    assert (load_texture ((resource_dir+"negz.jpg").c_str(), &tex));
    //*----------------------------------------------------------------------------------*/
    glfwMakeContextCurrent (window);

    
    int cube_V_location = glGetUniformLocation (cube_sp, "V");
    int cube_P_location = glGetUniformLocation (cube_sp, "P");
    //int cube_vertOut = glGetUniformLocation (cube_sp, "vertOut");
    
    /*-------------------------------CREATE GLOBAL CAMERA--------------------------------*/
    #define ONE_DEG_IN_RAD (2.0 * M_PI) / 360.0 // 0.017444444
    // input variables
    float near = 0.1f; // clipping plane
    float far = 100.0f; // clipping plane
    float fovy = 80.0f; // 67 degrees
    float aspect = (float)g_gl_width / (float)g_gl_height; // aspect ratio
    proj_mat = perspective (fovy, aspect, near, far);
    
    float cam_speed = 3.0f; // 1 unit per second
    float cam_heading_speed = 50.0f; // 30 degrees per second
    float cam_heading = 0.0f; // y-rotation in degrees
    mat4 T = translate (identity_mat4 (), vec3 (-cam_pos.v[0], -cam_pos.v[1], -cam_pos.v[2]));
    mat4 R = rotate_y_deg (identity_mat4 (), -cam_heading);
    versor q = quat_from_axis_deg (-cam_heading, 0.0f, 1.0f, 0.0f);
    view_mat = R * T;
    // keep track of some useful vectors that can be used for keyboard movement
    vec4 fwd (0.0f, 0.0f, -1.0f, 0.0f);
    vec4 rgt (1.0f, 0.0f, 0.0f, 0.0f);
    vec4 up (0.0f, 1.0f, 0.0f, 0.0f);
    
    
    
    /*---------------------------SET RENDERING DEFAULTS---------------------------*/
    glUseProgram (cube_sp);
    glUniformMatrix4fv (cube_V_location, 1, GL_FALSE, R.m);
    glUniformMatrix4fv (cube_P_location, 1, GL_FALSE, proj_mat.m);
    // unique model matrix for each sphere
    mat4 model_mat = identity_mat4 ();
    
    glEnable (GL_DEPTH_TEST); // enable depth-testing
    glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
    glEnable (GL_CULL_FACE); // cull face
    glCullFace (GL_BACK); // cull back face
    glFrontFace (GL_CCW); // set counter-clock-wise vertex order to mean the front
    glClearColor (0.2, 0.2, 0.2, 1.0); // grey background to help spot mistakes
    glViewport (0, 0, g_gl_width, g_gl_height);
    
    while (!glfwWindowShouldClose (window) && !glfwWindowShouldClose (window2)) {
        // update timers
        static double previous_seconds = glfwGetTime ();
        double current_seconds = glfwGetTime ();
        double elapsed_seconds = current_seconds - previous_seconds;
        previous_seconds = current_seconds;
        //_update_fps_counter (window);
        
        // wipe the drawing surface clear
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        // render a sky-box using the cube-map texture
        glDepthMask (GL_FALSE);
        glUseProgram (cube_sp);
        glActiveTexture (GL_TEXTURE0);
        glBindTexture (GL_TEXTURE_CUBE_MAP, cube_map_texture);
        glBindVertexArray (vao);
        glDrawArrays (GL_TRIANGLES, 0, 36);
        glDepthMask (GL_TRUE);
        
        //*---------------------------------Display for second window-------------------*/
        
        glfwMakeContextCurrent (window2);
        glUseProgram (square_sp);
        
        int cubemap_vert = glGetUniformLocation (square_sp, "cubeMap_texcoords");
        
        
        glEnable (GL_DEPTH_TEST); // enable depth-testing
        glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
        glEnable (GL_CULL_FACE); // cull face
        glCullFace (GL_BACK); // cull back face
        glFrontFace (GL_CCW); // set counter-clock-wise vertex order to mean the front
        glClearColor (0.3, 0.2, 0.3, 1.0); // grey background to help spot mistakes
        glViewport (0, 0, g_gl_width, g_gl_height);
        
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        glDepthMask (GL_FALSE);
        glUseProgram (square_sp);
        glBindVertexArray (vao_square);
        glDrawArrays (GL_TRIANGLES, 0, 6);
        glDepthMask (GL_TRUE);

        
        //*------------------------------GO back to cubemap window--------------------*/
        glfwMakeContextCurrent (window);
        
        // update other events like input handling
        glfwPollEvents ();
        
        // control keys
        bool cam_moved = false;
        vec3 move (0.0, 0.0, 0.0);
        float cam_yaw = 0.0f; // y-rotation in degrees
        float cam_pitch = 0.0f;
        float cam_roll = 0.0;
        if (glfwGetKey (window, GLFW_KEY_A)) {
            move.v[0] -= cam_speed * elapsed_seconds;
            cam_moved = true;
            print(move);
        }
        if (glfwGetKey (window, GLFW_KEY_D)) {
            move.v[0] += cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (window, GLFW_KEY_Q)) {
            move.v[1] += cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (window, GLFW_KEY_E)) {
            move.v[1] -= cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (window, GLFW_KEY_W)) {
            move.v[2] -= cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (window, GLFW_KEY_S)) {
            move.v[2] += cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (window, GLFW_KEY_LEFT)) {
            cam_yaw += cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_yaw = quat_from_axis_deg (
                                               cam_yaw, up.v[0], up.v[1], up.v[2]
                                               );
            q = q_yaw * q;
        }
        if (glfwGetKey (window, GLFW_KEY_RIGHT)) {
            cam_yaw -= cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_yaw = quat_from_axis_deg (
                                               cam_yaw, up.v[0], up.v[1], up.v[2]
                                               );
            q = q_yaw * q;
        }
        if (glfwGetKey (window, GLFW_KEY_UP)) {
            cam_pitch += cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_pitch = quat_from_axis_deg (
                                                 cam_pitch, rgt.v[0], rgt.v[1], rgt.v[2]
                                                 );
            q = q_pitch * q;
        }
        if (glfwGetKey (window, GLFW_KEY_DOWN)) {
            cam_pitch -= cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_pitch = quat_from_axis_deg (
                                                 cam_pitch, rgt.v[0], rgt.v[1], rgt.v[2]
                                                 );
            q = q_pitch * q;
        }
        if (glfwGetKey (window, GLFW_KEY_Z)) {
            cam_roll -= cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_roll = quat_from_axis_deg (
                                                cam_roll, fwd.v[0], fwd.v[1], fwd.v[2]
                                                );
            q = q_roll * q;
        }
        if (glfwGetKey (window, GLFW_KEY_C)) {
            cam_roll += cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_roll = quat_from_axis_deg (
                                                cam_roll, fwd.v[0], fwd.v[1], fwd.v[2]
                                                );
            q = q_roll * q;
        }
        // update view matrix
        if (cam_moved) {
            cam_heading += cam_yaw;
            
            // re-calculate local axes so can move fwd in dir cam is pointing
            R = quat_to_mat4 (q);
            fwd = R * vec4 (0.0, 0.0, -1.0, 0.0);
            rgt = R * vec4 (1.0, 0.0, 0.0, 0.0);
            up = R * vec4 (0.0, 1.0, 0.0, 0.0);
            
            cam_pos = cam_pos + vec3 (fwd) * -move.v[2];
            cam_pos = cam_pos + vec3 (up) * move.v[1];
            cam_pos = cam_pos + vec3 (rgt) * move.v[0];
            mat4 T = translate (identity_mat4 (), vec3 (cam_pos));
            
            view_mat = inverse (R) * inverse (T);
            //std::cout<<inverse(R).m<<std::endl;
            // cube-map view matrix has rotation, but not translation
            glUseProgram (cube_sp);
            glUniformMatrix4fv (cube_V_location, 1, GL_FALSE, inverse (R).m);
        }
        
        
        if (GLFW_PRESS == glfwGetKey (window, GLFW_KEY_ESCAPE)) {
            glfwSetWindowShouldClose (window, 1);
        }
        if (GLFW_PRESS == glfwGetKey (window2, GLFW_KEY_ESCAPE)) {
            glfwSetWindowShouldClose (window2, 1);
        }
        // put the stuff we've been drawing onto the display
        glfwSwapBuffers (window);
        
        glfwMakeContextCurrent (window2);
        glfwSwapBuffers (window2);
        glfwMakeContextCurrent (window);
    }
    
    // close GL context and any other GLFW resources
    glfwTerminate();
    return 0;
}
Exemple #17
0
/* don't set windows active in here, is used by renderwin too */
void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
{
	if (rv3d->persp == RV3D_CAMOB) {      /* obs/camera */
		if (v3d->camera) {
			BKE_object_where_is_calc(scene, v3d->camera);
			obmat_to_viewmat(rv3d, v3d->camera);
		}
		else {
			quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
			rv3d->viewmat[3][2] -= rv3d->dist;
		}
	}
	else {
		bool use_lock_ofs = false;


		/* should be moved to better initialize later on XXX */
		if (rv3d->viewlock & RV3D_LOCKED)
			ED_view3d_lock(rv3d);
		
		quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
		if (rv3d->persp == RV3D_PERSP) rv3d->viewmat[3][2] -= rv3d->dist;
		if (v3d->ob_centre) {
			Object *ob = v3d->ob_centre;
			float vec[3];
			
			copy_v3_v3(vec, ob->obmat[3]);
			if (ob->type == OB_ARMATURE && v3d->ob_centre_bone[0]) {
				bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, v3d->ob_centre_bone);
				if (pchan) {
					copy_v3_v3(vec, pchan->pose_mat[3]);
					mul_m4_v3(ob->obmat, vec);
				}
			}
			translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
			use_lock_ofs = true;
		}
		else if (v3d->ob_centre_cursor) {
			float vec[3];
			copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, v3d));
			translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
			use_lock_ofs = true;
		}
		else {
			translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
		}

		/* lock offset */
		if (use_lock_ofs) {
			float persmat[4][4], persinv[4][4];
			float vec[3];

			/* we could calculate the real persmat/persinv here
			 * but it would be unreliable so better to later */
			mul_m4_m4m4(persmat, rv3d->winmat, rv3d->viewmat);
			invert_m4_m4(persinv, persmat);

			mul_v2_v2fl(vec, rv3d->ofs_lock, rv3d->is_persp ? rv3d->dist : 1.0f);
			vec[2] = 0.0f;
			mul_mat3_m4_v3(persinv, vec);
			translate_m4(rv3d->viewmat, vec[0], vec[1], vec[2]);
		}
		/* end lock offset */
	}
}
Exemple #18
0
void m4_rotate_quat(mat4_t m, quat_t q)
{
	mat4_t rm;
	quat_to_mat4(rm, q);
	m4_mult(m, m, rm);
}
Exemple #19
0
static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated)
{
	GroupObject *go;
	Object *ob=NULL, **oblist=NULL, obcopy, *obcopylist=NULL;
	DupliObject *dob;
	ParticleDupliWeight *dw;
	ParticleSettings *part;
	ParticleData *pa;
	ChildParticle *cpa=NULL;
	ParticleKey state;
	ParticleCacheKey *cache;
	float ctime, pa_time, scale = 1.0f;
	float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size=0.0;
	float (*obmat)[4], (*oldobmat)[4];
	int a, b, counter, hair = 0;
	int totpart, totchild, totgroup=0 /*, pa_num */;

	int no_draw_flag = PARS_UNEXIST;

	if (psys==NULL) return;
	
	/* simple preventing of too deep nested groups */
	if (level>MAX_DUPLI_RECUR) return;
	
	part=psys->part;

	if (part==NULL)
		return;

	if (!psys_check_enabled(par, psys))
		return;

	if (G.rendering == 0)
		no_draw_flag |= PARS_NO_DISP;
	
	ctime = BKE_curframe(scene); /* NOTE: in old animsys, used parent object's timeoffset... */

	totpart = psys->totpart;
	totchild = psys->totchild;

	BLI_srandom(31415926 + psys->seed);

	if ((psys->renderdata || part->draw_as==PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
		ParticleSimulationData sim= {NULL};
		sim.scene= scene;
		sim.ob= par;
		sim.psys= psys;
		sim.psmd= psys_get_modifier(par, psys);
		/* make sure emitter imat is in global coordinates instead of render view coordinates */
		invert_m4_m4(par->imat, par->obmat);

		/* first check for loops (particle system object used as dupli object) */
		if (part->ren_as == PART_DRAW_OB) {
			if (ELEM(part->dup_ob, NULL, par))
				return;
		}
		else { /*PART_DRAW_GR */
			if (part->dup_group == NULL || part->dup_group->gobject.first == NULL)
				return;

			for (go=part->dup_group->gobject.first; go; go=go->next)
				if (go->ob == par)
					return;
		}

		/* if we have a hair particle system, use the path cache */
		if (part->type == PART_HAIR) {
			if (psys->flag & PSYS_HAIR_DONE)
				hair= (totchild == 0 || psys->childcache) && psys->pathcache;
			if (!hair)
				return;
			
			/* we use cache, update totchild according to cached data */
			totchild = psys->totchildcache;
			totpart = psys->totcached;
		}

		psys_check_group_weights(part);

		psys->lattice = psys_get_lattice(&sim);

		/* gather list of objects or single object */
		if (part->ren_as==PART_DRAW_GR) {
			group_handle_recalc_and_update(scene, par, part->dup_group);

			if (part->draw & PART_DRAW_COUNT_GR) {
				for (dw=part->dupliweights.first; dw; dw=dw->next)
					totgroup += dw->count;
			}
			else {
				for (go=part->dup_group->gobject.first; go; go=go->next)
					totgroup++;
			}

			/* we also copy the actual objects to restore afterwards, since
			 * where_is_object_time will change the object which breaks transform */
			oblist = MEM_callocN(totgroup*sizeof(Object *), "dupgroup object list");
			obcopylist = MEM_callocN(totgroup*sizeof(Object), "dupgroup copy list");

			
			if (part->draw & PART_DRAW_COUNT_GR && totgroup) {
				dw = part->dupliweights.first;

				for (a=0; a<totgroup; dw=dw->next) {
					for (b=0; b<dw->count; b++, a++) {
						oblist[a] = dw->ob;
						obcopylist[a] = *dw->ob;
					}
				}
			}
			else {
				go = part->dup_group->gobject.first;
				for (a=0; a<totgroup; a++, go=go->next) {
					oblist[a] = go->ob;
					obcopylist[a] = *go->ob;
				}
			}
		}
		else {
			ob = part->dup_ob;
			obcopy = *ob;
		}

		if (totchild==0 || part->draw & PART_DRAW_PARENT)
			a = 0;
		else
			a = totpart;

		for (pa=psys->particles,counter=0; a<totpart+totchild; a++,pa++,counter++) {
			if (a<totpart) {
				/* handle parent particle */
				if (pa->flag & no_draw_flag)
					continue;

				/* pa_num = pa->num; */ /* UNUSED */
				pa_time = pa->time;
				size = pa->size;
			}
			else {
				/* handle child particle */
				cpa = &psys->child[a - totpart];

				/* pa_num = a; */ /* UNUSED */
				pa_time = psys->particles[cpa->parent].time;
				size = psys_get_child_size(psys, cpa, ctime, NULL);
			}

			/* some hair paths might be non-existent so they can't be used for duplication */
			if (hair &&
				((a < totpart && psys->pathcache[a]->steps < 0) ||
				(a >= totpart && psys->childcache[a-totpart]->steps < 0)))
				continue;

			if (part->ren_as==PART_DRAW_GR) {
				/* prevent divide by zero below [#28336] */
				if (totgroup == 0)
					continue;

				/* for groups, pick the object based on settings */
				if (part->draw&PART_DRAW_RAND_GR)
					b= BLI_rand() % totgroup;
				else
					b= a % totgroup;

				ob = oblist[b];
				obmat = oblist[b]->obmat;
				oldobmat = obcopylist[b].obmat;
			}
			else {
				obmat= ob->obmat;
				oldobmat= obcopy.obmat;
			}

			if (hair) {
				/* hair we handle separate and compute transform based on hair keys */
				if (a < totpart) {
					cache = psys->pathcache[a];
					psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale);
				}
				else {
					cache = psys->childcache[a-totpart];
					psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale);
				}

				copy_v3_v3(pamat[3], cache->co);
				pamat[3][3]= 1.0f;
				
			}
			else {
				/* first key */
				state.time = ctime;
				if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
					continue;
				}
				else {
					float tquat[4];
					normalize_qt_qt(tquat, state.rot);
					quat_to_mat4(pamat, tquat);
					copy_v3_v3(pamat[3], state.co);
					pamat[3][3]= 1.0f;
				}
			}

			if (part->ren_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
				for (go= part->dup_group->gobject.first, b=0; go; go= go->next, b++) {

					copy_m4_m4(tmat, oblist[b]->obmat);
					/* apply particle scale */
					mul_mat3_m4_fl(tmat, size*scale);
					mul_v3_fl(tmat[3], size*scale);
					/* group dupli offset, should apply after everything else */
					if (!is_zero_v3(part->dup_group->dupli_ofs))
						sub_v3_v3v3(tmat[3], tmat[3], part->dup_group->dupli_ofs);
					/* individual particle transform */
					mult_m4_m4m4(tmat, pamat, tmat);

					if (par_space_mat)
						mult_m4_m4m4(mat, par_space_mat, tmat);
					else
						copy_m4_m4(mat, tmat);

					dob= new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated);
					copy_m4_m4(dob->omat, obcopylist[b].obmat);
					if (G.rendering)
						psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
				}
			}
			else {
				/* to give ipos in object correct offset */
				where_is_object_time(scene, ob, ctime-pa_time);

				copy_v3_v3(vec, obmat[3]);
				obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;

				/* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */
				if ((part->draw & PART_DRAW_ROTATE_OB) == 0) {
					float xvec[3], q[4];
					xvec[0] = -1.f;
					xvec[1] = xvec[2] = 0;
					vec_to_quat(q, xvec, ob->trackflag, ob->upflag);
					quat_to_mat4(obmat, q);
					obmat[3][3]= 1.0f;
				}
				
				/* Normal particles and cached hair live in global space so we need to
				 * remove the real emitter's transformation before 2nd order duplication.
				 */
				if (par_space_mat && GS(id->name) != ID_GR)
					mult_m4_m4m4(mat, psys->imat, pamat);
				else
					copy_m4_m4(mat, pamat);

				mult_m4_m4m4(tmat, mat, obmat);
				mul_mat3_m4_fl(tmat, size*scale);

				if (par_space_mat)
					mult_m4_m4m4(mat, par_space_mat, tmat);
				else
					copy_m4_m4(mat, tmat);

				if (part->draw & PART_DRAW_GLOBAL_OB)
					add_v3_v3v3(mat[3], mat[3], vec);

				dob= new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated);
				copy_m4_m4(dob->omat, oldobmat);
				if (G.rendering)
					psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
			}
		}

		/* restore objects since they were changed in where_is_object_time */
		if (part->ren_as==PART_DRAW_GR) {
			for (a=0; a<totgroup; a++)
				*(oblist[a])= obcopylist[a];
		}
		else
			*ob= obcopy;
	}

	/* clean up */
	if (oblist)
		MEM_freeN(oblist);
	if (obcopylist)
		MEM_freeN(obcopylist);

	if (psys->lattice) {
		end_latt_deform(psys->lattice);
		psys->lattice = NULL;
	}
}
void skeleton_animate  (
	Skeleton_Node* node,
	double anim_time,
	mat4 parent_mat,
	mat4* bone_offset_mats,
	mat4* bone_animation_mats
) {
	
	assert (node);
	
	/* the animation of a node after inheriting its parent's animation */
	mat4 our_mat = parent_mat;
	
	
	
	/* the animation for a particular bone at this time */
	mat4 local_anim = identity_mat4 ();
	
	mat4 node_T = identity_mat4 ();
	if (node->num_pos_keys > 0) {
		int prev_key = 0;
		int next_key = 0;
		for (int i = 0; i < node->num_pos_keys - 1; i++) {
			prev_key = i;
			next_key = i + 1;
			if (node->pos_key_times[next_key] >= anim_time) {
				break;
			}
		}
		float total_t = node->pos_key_times[next_key] - node->pos_key_times[prev_key];
		float t = (anim_time - node->pos_key_times[prev_key]) / total_t;
		vec3 vi = node->pos_keys[prev_key];
		vec3 vf = node->pos_keys[next_key];
		vec3 lerped = vi * (1.0f - t) + vf * t;
		node_T = translate (identity_mat4 (), lerped);
	}
	
	mat4 node_R = identity_mat4 ();
	if (node->num_rot_keys > 0) {
		// find next and previous keys
		int prev_key = 0;
		int next_key = 0;
		for (int i = 0; i < node->num_rot_keys - 1; i++) {
			prev_key = i;
			next_key = i + 1;
			if (node->rot_key_times[next_key] >= anim_time) {
				break;
			}
		}
		float total_t = node->rot_key_times[next_key] - node->rot_key_times[prev_key];
		float t = (anim_time - node->rot_key_times[prev_key]) / total_t;
		versor qi = node->rot_keys[prev_key];
		versor qf = node->rot_keys[next_key];
		versor slerped = slerp (qi, qf, t);
		node_R = quat_to_mat4 (slerped);
	}
	
	local_anim = node_T * node_R;
	
	// if node has a weighted bone...
	int bone_i = node->bone_index;
	if (bone_i > -1) {
		// ... then get offset matrices
		mat4 bone_offset = bone_offset_mats[bone_i];
		
		our_mat = parent_mat * local_anim;
		bone_animation_mats[bone_i] = parent_mat * local_anim * bone_offset;
	}
	for (int i = 0; i < node->num_children; i++) {
		skeleton_animate (
			node->children[i],
			anim_time,
			our_mat,
			bone_offset_mats,
			bone_animation_mats
		);
	}
}
/**
 * Iterates over ALL objects in the scene and all of its sets, including
 * making all duplis(not only metas). Copies metas to mainb array.
 * Computes bounding boxes for building BVH. */
static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob)
{
	Scene *sce_iter = scene;
	Base *base;
	Object *bob;
	MetaBall *mb;
	const MetaElem *ml;
	float obinv[4][4], obmat[4][4];
	unsigned int i;
	int obnr, zero_size = 0;
	char obname[MAX_ID_NAME];
	SceneBaseIter iter;

	copy_m4_m4(obmat, ob->obmat);   /* to cope with duplicators from BKE_scene_base_iter_next */
	invert_m4_m4(obinv, ob->obmat);

	BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');

	/* make main array */
	BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
	while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) {
		if (bob->type == OB_MBALL) {
			zero_size = 0;
			ml = NULL;

			if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) {
				mb = ob->data;

				if (mb->editelems) ml = mb->editelems->first;
				else ml = mb->elems.first;
			}
			else {
				char name[MAX_ID_NAME];
				int nr;

				BLI_split_name_num(name, &nr, bob->id.name + 2, '.');
				if (STREQ(obname, name)) {
					mb = bob->data;

					if (mb->editelems) ml = mb->editelems->first;
					else ml = mb->elems.first;
				}
			}

			/* when metaball object has zero scale, then MetaElem to this MetaBall
			 * will not be put to mainb array */
			if (has_zero_axis_m4(bob->obmat)) {
				zero_size = 1;
			}
			else if (bob->parent) {
				struct Object *pob = bob->parent;
				while (pob) {
					if (has_zero_axis_m4(pob->obmat)) {
						zero_size = 1;
						break;
					}
					pob = pob->parent;
				}
			}

			if (zero_size) {
				while (ml) {
					ml = ml->next;
				}
			}
			else {
				while (ml) {
					if (!(ml->flag & MB_HIDE)) {
						float pos[4][4], rot[4][4];
						float expx, expy, expz;
						float tempmin[3], tempmax[3];

						MetaElem *new_ml;

						/* make a copy because of duplicates */
						new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem));
						*(new_ml) = *ml;
						new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox));
						new_ml->mat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));
						new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float));

						/* too big stiffness seems only ugly due to linear interpolation
						* no need to have possibility for too big stiffness */
						if (ml->s > 10.0f) new_ml->s = 10.0f;
						else new_ml->s = ml->s;

						/* if metaball is negative, set stiffness negative */
						if (new_ml->flag & MB_NEGATIVE) new_ml->s = -new_ml->s;

						/* Translation of MetaElem */
						unit_m4(pos);
						pos[3][0] = ml->x;
						pos[3][1] = ml->y;
						pos[3][2] = ml->z;

						/* Rotation of MetaElem is stored in quat */
						quat_to_mat4(rot, ml->quat);

						/* basis object space -> world -> ml object space -> position -> rotation -> ml local space */
						mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot);
						/* ml local space -> basis object space */
						invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat);

						/* rad2 is inverse of squared radius */
						new_ml->rad2 = 1 / (ml->rad * ml->rad);

						/* initial dimensions = radius */
						expx = ml->rad;
						expy = ml->rad;
						expz = ml->rad;

						switch (ml->type) {
							case MB_BALL:
								break;
							case MB_CUBE: /* cube is "expanded" by expz, expy and expx */
								expz += ml->expz;
								/* fall through */
							case MB_PLANE: /* plane is "expanded" by expy and expx */
								expy += ml->expy;
								/* fall through */
							case MB_TUBE: /* tube is "expanded" by expx */
								expx += ml->expx;
								break;
							case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */
								expx *= ml->expx;
								expy *= ml->expy;
								expz *= ml->expz;
								break;
						}

						/* untransformed Bounding Box of MetaElem */
						/* TODO, its possible the elem type has been changed and the exp* values can use a fallback */
						copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz);  /* 0 */
						copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz);  /* 1 */
						copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz);  /* 2 */
						copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz);  /* 3 */
						copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz);  /* 4 */
						copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz);  /* 5 */
						copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz);  /* 6 */
						copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz);  /* 7 */

						/* transformation of Metalem bb */
						for (i = 0; i < 8; i++)
							mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]);

						/* find max and min of transformed bb */
						INIT_MINMAX(tempmin, tempmax);
						for (i = 0; i < 8; i++) {
							DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax);
						}

						/* set only point 0 and 6 - AABB of Metaelem */
						copy_v3_v3(new_ml->bb->vec[0], tempmin);
						copy_v3_v3(new_ml->bb->vec[6], tempmax);

						/* add new_ml to mainb[] */
						if (UNLIKELY(process->totelem == process->mem)) {
							process->mem = process->mem * 2 + 10;
							process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem);
						}
						process->mainb[process->totelem++] = new_ml;
					}
					ml = ml->next;
				}
			}
		}
	}

	/* compute AABB of all Metaelems */
	if (process->totelem > 0) {
		copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]);
		copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]);
		for (i = 1; i < process->totelem; i++)
			make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb);
	}
}
Exemple #22
0
void Camera::recalc_axes() {
	quat_to_mat4 (R.m, quaternion);
	fwd = R * FORWARD;
	rgt = R * RIGHT;
	up = R * UP;
}
int main () {
	// start GL context with helper libraries
	assert (glfwInit ());
	
	/* We must specify 3.2 core if on Apple OS X -- other O/S can specify
	 anything here. I defined 'APPLE' in the makefile for OS X */
#ifdef APPLE
	glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2);
	glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#endif
	GLFWwindow* window = glfwCreateWindow (
		g_viewport_width, g_viewport_height, "GUI Panels", NULL, NULL);
	glfwSetWindowSizeCallback (window, glfw_window_size_callback);
	glfwMakeContextCurrent (window);
	glewExperimental = GL_TRUE;
	glewInit ();
	const GLubyte* renderer = glGetString (GL_RENDERER); // get renderer string
	const GLubyte* version = glGetString (GL_VERSION); // version as a string
	printf ("Renderer: %s\n", renderer);
	printf ("OpenGL version supported %s\n", version);
	
	// create a 2d panel. from 2 triangles = 6 xy coords.
	float points[] = {
		-1.0f, -1.0f,
		 1.0f, -1.0f,
		-1.0f,  1.0f,
		-1.0f,  1.0f,
		 1.0f, -1.0f,
		 1.0f,  1.0f
	};
	// for ground plane we can just re-use panel points but y is now z
	GLuint vp_vbo, vao;
	glGenBuffers (1, &vp_vbo);
	glBindBuffer (GL_ARRAY_BUFFER, vp_vbo);
	glBufferData (GL_ARRAY_BUFFER, sizeof (points), points, GL_STATIC_DRAW);
	glGenVertexArrays (1, &vao);
	glBindVertexArray (vao);
	// note: vertex buffer is already bound
	glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
	glEnableVertexAttribArray (0);

	// create a 3d camera to move in 3d so that we can tell that the panel is 2d
	// keep track of some useful vectors that can be used for keyboard movement
	vec4 fwd (0.0f, 0.0f, -1.0f, 0.0f);
	vec4 rgt (1.0f, 0.0f, 0.0f, 0.0f);
	vec4 up (0.0f, 1.0f, 0.0f, 0.0f);
	vec3 cam_pos (0.0f, 1.0f, 5.0f);
	mat4 T_inv = translate (identity_mat4 (), cam_pos);
	// point slightly downwards to see the plane
	versor quaternion = quat_from_axis_deg (0.0f, 1.0f, 0.0f, 0.0f);
	mat4 R_inv = quat_to_mat4 (quaternion);
	// combine the inverse rotation and transformation to make a view matrix
	V = inverse (R_inv) * inverse (T_inv);
	// projection matrix
	P = perspective (
		67.0f, (float)g_viewport_width / (float)g_viewport_height, 0.1f, 100.0f);
	const float cam_speed = 3.0f; // 1 unit per second
	const float cam_heading_speed = 50.0f; // 30 degrees per second
	
	create_ground_plane_shaders ();
	create_gui_shaders ();
	
	// textures for ground plane and gui
	GLuint gp_tex, gui_tex;
	assert (load_texture ("tile2-diamonds256x256.png", &gp_tex));
	assert (load_texture ("skulluvmap.png", &gui_tex));
	
	// rendering defaults
	glDepthFunc (GL_LESS); // set depth function but don't enable yet
	glEnable (GL_CULL_FACE); // cull face
	glCullFace (GL_BACK); // cull back face
	glFrontFace (GL_CCW); // GL_CCW for counter clock-wise
	
	// absolute panel dimensions in pixels
	const float panel_width = 256.0f;
	const float panel_height = 256.0f;
	
	glViewport (0, 0, g_viewport_width, g_viewport_height);
	
	// start main rendering loop
	while (!glfwWindowShouldClose (window)) {
		// update timers
		static double previous_seconds = glfwGetTime ();
		double current_seconds = glfwGetTime ();
		double elapsed_seconds = current_seconds - previous_seconds;
		previous_seconds = current_seconds;

		bool cam_moved = false;
		vec3 move (0.0, 0.0, 0.0);
		
		// wipe the drawing surface clear
		glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		// draw ground plane. note: depth test is enabled here
		glEnable (GL_DEPTH_TEST);
		glActiveTexture (GL_TEXTURE0);
		glBindTexture (GL_TEXTURE_2D, gp_tex);
		glUseProgram (gp_sp);
		glBindVertexArray (vao);
		glDrawArrays (GL_TRIANGLES, 0, 6);
		
		// draw GUI panel. note: depth test is disabled here and drawn AFTER scene
		glDisable (GL_DEPTH_TEST);
		glActiveTexture (GL_TEXTURE0);
		glBindTexture (GL_TEXTURE_2D, gui_tex);
		glUseProgram (gui_sp);
		// resize panel to size in pixels
		float x_scale = panel_width / g_viewport_width;
		float y_scale = panel_height / g_viewport_height;
		glUniform2f (gui_scale_loc, x_scale, y_scale);
		glBindVertexArray (vao);
		glDrawArrays (GL_TRIANGLES, 0, 6);
		
		// update other events like input handling 
		glfwPollEvents ();
		if (GLFW_PRESS == glfwGetKey (window, GLFW_KEY_ESCAPE)) {
			glfwSetWindowShouldClose (window, 1);
		}
		float cam_yaw = 0.0f; // y-rotation in degrees
		float cam_pitch = 0.0f;
		float cam_roll = 0.0;
		if (glfwGetKey (window, GLFW_KEY_A)) {
			move.v[0] -= cam_speed * elapsed_seconds;
			cam_moved = true;
		}
		if (glfwGetKey (window, GLFW_KEY_D)) {
			move.v[0] += cam_speed * elapsed_seconds;
			cam_moved = true;
		}
		if (glfwGetKey (window, GLFW_KEY_Q)) {
			move.v[1] += cam_speed * elapsed_seconds;
			cam_moved = true;
		}
		if (glfwGetKey (window, GLFW_KEY_E)) {
			move.v[1] -= cam_speed * elapsed_seconds;
			cam_moved = true;
		}
		if (glfwGetKey (window, GLFW_KEY_W)) {
			move.v[2] -= cam_speed * elapsed_seconds;
			cam_moved = true;
		}
		if (glfwGetKey (window, GLFW_KEY_S)) {
			move.v[2] += cam_speed * elapsed_seconds;
			cam_moved = true;
		}
		if (glfwGetKey (window, GLFW_KEY_LEFT)) {
			cam_yaw += cam_heading_speed * elapsed_seconds;
			cam_moved = true;
			versor q_yaw = quat_from_axis_deg (cam_yaw, up.v[0], up.v[1], up.v[2]);
			quaternion = q_yaw * quaternion;
		}
		if (glfwGetKey (window, GLFW_KEY_RIGHT)) {
			cam_yaw -= cam_heading_speed * elapsed_seconds;
			cam_moved = true;
			versor q_yaw = quat_from_axis_deg (cam_yaw, up.v[0], up.v[1], up.v[2]);
			quaternion = q_yaw * quaternion;
		}
		if (glfwGetKey (window, GLFW_KEY_UP)) {
			cam_pitch += cam_heading_speed * elapsed_seconds;
			cam_moved = true;
			versor q_pitch = quat_from_axis_deg (
				cam_pitch, rgt.v[0], rgt.v[1], rgt.v[2]);
			quaternion = q_pitch * quaternion;
		}
		if (glfwGetKey (window, GLFW_KEY_DOWN)) {
			cam_pitch -= cam_heading_speed * elapsed_seconds;
			cam_moved = true;
			versor q_pitch = quat_from_axis_deg (
				cam_pitch, rgt.v[0], rgt.v[1], rgt.v[2]);
			quaternion = q_pitch * quaternion;
		}
		if (glfwGetKey (window, GLFW_KEY_Z)) {
			cam_roll -= cam_heading_speed * elapsed_seconds;
			cam_moved = true;
			versor q_roll = quat_from_axis_deg (
				cam_roll, fwd.v[0], fwd.v[1], fwd.v[2]);
			quaternion = q_roll * quaternion;
		}
		if (glfwGetKey (window, GLFW_KEY_C)) {
			cam_roll += cam_heading_speed * elapsed_seconds;
			cam_moved = true;
			versor q_roll = quat_from_axis_deg (
				cam_roll, fwd.v[0], fwd.v[1], fwd.v[2]);
			quaternion = q_roll * quaternion;
		}
		// update view matrix
		if (cam_moved) {
			// re-calculate local axes so can move fwd in dir cam is pointing
			R_inv = quat_to_mat4 (quaternion);
			fwd = R_inv * vec4 (0.0, 0.0, -1.0, 0.0);
			rgt = R_inv * vec4 (1.0, 0.0, 0.0, 0.0);
			up = R_inv * vec4 (0.0, 1.0, 0.0, 0.0);
			
			cam_pos = cam_pos + vec3 (fwd) * -move.v[2];
			cam_pos = cam_pos + vec3 (up) * move.v[1];
			cam_pos = cam_pos + vec3 (rgt) * move.v[0];
			T_inv = translate (identity_mat4 (), cam_pos);
			
			V = inverse (R_inv) * inverse (T_inv);
			glUseProgram (gp_sp);
			glUniformMatrix4fv (gp_V_loc, 1, GL_FALSE, V.m);
		}
		// put the stuff we've been drawing onto the display
		glfwSwapBuffers (window);
	}
	// done
	 glfwTerminate();
	return 0;
}
Exemple #24
0
/* OB_DUPLIPARTS */
static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys)
{
	Scene *scene = ctx->scene;
	Object *par = ctx->object;
	bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER;
	bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);

	GroupObject *go;
	Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL;
	DupliObject *dob;
	ParticleDupliWeight *dw;
	ParticleSettings *part;
	ParticleData *pa;
	ChildParticle *cpa = NULL;
	ParticleKey state;
	ParticleCacheKey *cache;
	float ctime, pa_time, scale = 1.0f;
	float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0;
	float (*obmat)[4];
	int a, b, hair = 0;
	int totpart, totchild, totgroup = 0 /*, pa_num */;
	const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene);

	int no_draw_flag = PARS_UNEXIST;

	if (psys == NULL) return;

	part = psys->part;

	if (part == NULL)
		return;

	if (!psys_check_enabled(par, psys))
		return;

	if (!for_render)
		no_draw_flag |= PARS_NO_DISP;

	ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */

	totpart = psys->totpart;
	totchild = psys->totchild;

	BLI_srandom((unsigned int)(31415926 + psys->seed));

	if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
		ParticleSimulationData sim = {NULL};
		sim.scene = scene;
		sim.ob = par;
		sim.psys = psys;
		sim.psmd = psys_get_modifier(par, psys);
		/* make sure emitter imat is in global coordinates instead of render view coordinates */
		invert_m4_m4(par->imat, par->obmat);

		/* first check for loops (particle system object used as dupli object) */
		if (part->ren_as == PART_DRAW_OB) {
			if (ELEM(part->dup_ob, NULL, par))
				return;
		}
		else { /*PART_DRAW_GR */
			if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject))
				return;

			if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) {
				return;
			}
		}

		/* if we have a hair particle system, use the path cache */
		if (part->type == PART_HAIR) {
			if (psys->flag & PSYS_HAIR_DONE)
				hair = (totchild == 0 || psys->childcache) && psys->pathcache;
			if (!hair)
				return;

			/* we use cache, update totchild according to cached data */
			totchild = psys->totchildcache;
			totpart = psys->totcached;
		}

		psys_check_group_weights(part);

		psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);

		/* gather list of objects or single object */
		if (part->ren_as == PART_DRAW_GR) {
			if (ctx->do_update) {
				BKE_group_handle_recalc_and_update(ctx->eval_ctx, scene, par, part->dup_group);
			}

			if (part->draw & PART_DRAW_COUNT_GR) {
				for (dw = part->dupliweights.first; dw; dw = dw->next)
					totgroup += dw->count;
			}
			else {
				for (go = part->dup_group->gobject.first; go; go = go->next)
					totgroup++;
			}

			/* we also copy the actual objects to restore afterwards, since
			 * BKE_object_where_is_calc_time will change the object which breaks transform */
			oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list");
			obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list");

			if (part->draw & PART_DRAW_COUNT_GR && totgroup) {
				dw = part->dupliweights.first;

				for (a = 0; a < totgroup; dw = dw->next) {
					for (b = 0; b < dw->count; b++, a++) {
						oblist[a] = dw->ob;
						obcopylist[a] = *dw->ob;
					}
				}
			}
			else {
				go = part->dup_group->gobject.first;
				for (a = 0; a < totgroup; a++, go = go->next) {
					oblist[a] = go->ob;
					obcopylist[a] = *go->ob;
				}
			}
		}
		else {
			ob = part->dup_ob;
			obcopy = *ob;
		}

		if (totchild == 0 || part->draw & PART_DRAW_PARENT)
			a = 0;
		else
			a = totpart;

		for (pa = psys->particles; a < totpart + totchild; a++, pa++) {
			if (a < totpart) {
				/* handle parent particle */
				if (pa->flag & no_draw_flag)
					continue;

				/* pa_num = pa->num; */ /* UNUSED */
				pa_time = pa->time;
				size = pa->size;
			}
			else {
				/* handle child particle */
				cpa = &psys->child[a - totpart];

				/* pa_num = a; */ /* UNUSED */
				pa_time = psys->particles[cpa->parent].time;
				size = psys_get_child_size(psys, cpa, ctime, NULL);
			}

			/* some hair paths might be non-existent so they can't be used for duplication */
			if (hair && psys->pathcache &&
			    ((a < totpart && psys->pathcache[a]->segments < 0) ||
			     (a >= totpart && psys->childcache[a - totpart]->segments < 0)))
			{
				continue;
			}

			if (part->ren_as == PART_DRAW_GR) {
				/* prevent divide by zero below [#28336] */
				if (totgroup == 0)
					continue;

				/* for groups, pick the object based on settings */
				if (part->draw & PART_DRAW_RAND_GR)
					b = BLI_rand() % totgroup;
				else
					b = a % totgroup;

				ob = oblist[b];
				obmat = oblist[b]->obmat;
			}
			else {
				obmat = ob->obmat;
			}

			if (hair) {
				/* hair we handle separate and compute transform based on hair keys */
				if (a < totpart) {
					cache = psys->pathcache[a];
					psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale);
				}
				else {
					cache = psys->childcache[a - totpart];
					psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale);
				}

				copy_v3_v3(pamat[3], cache->co);
				pamat[3][3] = 1.0f;

			}
			else {
				/* first key */
				state.time = ctime;
				if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
					continue;
				}
				else {
					float tquat[4];
					normalize_qt_qt(tquat, state.rot);
					quat_to_mat4(pamat, tquat);
					copy_v3_v3(pamat[3], state.co);
					pamat[3][3] = 1.0f;
				}
			}

			if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
				for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) {

					copy_m4_m4(tmat, oblist[b]->obmat);
					/* apply particle scale */
					mul_mat3_m4_fl(tmat, size * scale);
					mul_v3_fl(tmat[3], size * scale);
					/* group dupli offset, should apply after everything else */
					if (!is_zero_v3(part->dup_group->dupli_ofs))
						sub_v3_v3(tmat[3], part->dup_group->dupli_ofs);
					/* individual particle transform */
					mul_m4_m4m4(mat, pamat, tmat);

					dob = make_dupli(ctx, go->ob, mat, a, false, false);
					dob->particle_system = psys;
					if (use_texcoords)
						psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
				}
			}
			else {
				/* to give ipos in object correct offset */
				BKE_object_where_is_calc_time(scene, ob, ctime - pa_time);

				copy_v3_v3(vec, obmat[3]);
				obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;

				/* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */
				if ((part->draw & PART_DRAW_ROTATE_OB) == 0) {
					float xvec[3], q[4], size_mat[4][4], original_size[3];

					mat4_to_size(original_size, obmat);
					size_to_mat4(size_mat, original_size);

					xvec[0] = -1.f;
					xvec[1] = xvec[2] = 0;
					vec_to_quat(q, xvec, ob->trackflag, ob->upflag);
					quat_to_mat4(obmat, q);
					obmat[3][3] = 1.0f;

					/* add scaling if requested */
					if ((part->draw & PART_DRAW_NO_SCALE_OB) == 0)
						mul_m4_m4m4(obmat, obmat, size_mat);
				}
				else if (part->draw & PART_DRAW_NO_SCALE_OB) {
					/* remove scaling */
					float size_mat[4][4], original_size[3];

					mat4_to_size(original_size, obmat);
					size_to_mat4(size_mat, original_size);
					invert_m4(size_mat);

					mul_m4_m4m4(obmat, obmat, size_mat);
				}

				mul_m4_m4m4(tmat, pamat, obmat);
				mul_mat3_m4_fl(tmat, size * scale);

				copy_m4_m4(mat, tmat);

				if (part->draw & PART_DRAW_GLOBAL_OB)
					add_v3_v3v3(mat[3], mat[3], vec);

				dob = make_dupli(ctx, ob, mat, a, false, false);
				dob->particle_system = psys;
				if (use_texcoords)
					psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
				/* XXX blender internal needs this to be set to dupligroup to render
				 * groups correctly, but we don't want this hack for cycles */
				if (dupli_type_hack && ctx->group)
					dob->type = OB_DUPLIGROUP;
			}
		}

		/* restore objects since they were changed in BKE_object_where_is_calc_time */
		if (part->ren_as == PART_DRAW_GR) {
			for (a = 0; a < totgroup; a++)
				*(oblist[a]) = obcopylist[a];
		}
		else
			*ob = obcopy;
	}

	/* clean up */
	if (oblist)
		MEM_freeN(oblist);
	if (obcopylist)
		MEM_freeN(obcopylist);

	if (psys->lattice_deform_data) {
		end_latt_deform(psys->lattice_deform_data);
		psys->lattice_deform_data = NULL;
	}
}
int main () {
    /*--------------------------------START OPENGL--------------------------------*/
    assert (restart_gl_log ());
    // start GL context and O/S window using the GLFW helper library
    assert (start_gl ());
    // set a function to be called when the mouse is clicked
    glfwSetMouseButtonCallback (g_window, glfw_mouse_click_callback);
    /*------------------------------CREATE GEOMETRY-------------------------------*/
    GLfloat* vp = NULL; // array of vertex points
    GLfloat* vn = NULL; // array of vertex normals
    GLfloat* vt = NULL; // array of texture coordinates
    int g_point_count = 0;
    assert (load_obj_file (MESH_FILE, vp, vt, vn, g_point_count));

    GLuint vao;
    glGenVertexArrays (1, &vao);
    glBindVertexArray (vao);

    GLuint points_vbo;
    if (NULL != vp) {
        glGenBuffers (1, &points_vbo);
        glBindBuffer (GL_ARRAY_BUFFER, points_vbo);
        glBufferData (
            GL_ARRAY_BUFFER, 3 * g_point_count * sizeof (GLfloat), vp, GL_STATIC_DRAW
        );
        glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
        glEnableVertexAttribArray (0);
    }

    /*-------------------------------CREATE SHADERS-------------------------------*/
    GLuint shader_programme = create_programme_from_files (
                                  VERTEX_SHADER_FILE, FRAGMENT_SHADER_FILE
                              );
    int model_mat_location = glGetUniformLocation (shader_programme, "model");
    int view_mat_location = glGetUniformLocation (shader_programme, "view");
    int proj_mat_location = glGetUniformLocation (shader_programme, "proj");
    int blue_location = glGetUniformLocation (shader_programme, "blue");

    /*-------------------------------CREATE CAMERA--------------------------------*/
#define ONE_DEG_IN_RAD (2.0 * M_PI) / 360.0 // 0.017444444
    // input variables
    float near = 0.1f; // clipping plane
    float far = 100.0f; // clipping plane
    float fovy = 67.0f; // 67 degrees
    float aspect = (float)g_gl_width / (float)g_gl_height; // aspect ratio
    proj_mat = perspective (fovy, aspect, near, far);

    float cam_speed = 3.0f; // 1 unit per second
    float cam_heading_speed = 50.0f; // 30 degrees per second
    float cam_heading = 0.0f; // y-rotation in degrees
    mat4 T = translate (
                 identity_mat4 (), vec3 (-cam_pos.v[0], -cam_pos.v[1], -cam_pos.v[2])
             );
    mat4 R = rotate_y_deg (identity_mat4 (), -cam_heading);
    versor q = quat_from_axis_deg (-cam_heading, 0.0f, 1.0f, 0.0f);
    view_mat = R * T;
    // keep track of some useful vectors that can be used for keyboard movement
    vec4 fwd (0.0f, 0.0f, -1.0f, 0.0f);
    vec4 rgt (1.0f, 0.0f, 0.0f, 0.0f);
    vec4 up (0.0f, 1.0f, 0.0f, 0.0f);

    /*---------------------------SET RENDERING DEFAULTS---------------------------*/
    glUseProgram (shader_programme);
    glUniformMatrix4fv (view_mat_location, 1, GL_FALSE, view_mat.m);
    glUniformMatrix4fv (proj_mat_location, 1, GL_FALSE, proj_mat.m);
    // unique model matrix for each sphere
    mat4 model_mats[NUM_SPHERES];
    for (int i = 0; i < NUM_SPHERES; i++) {
        model_mats[i] = translate (identity_mat4 (), sphere_pos_wor[i]);
    }

    glEnable (GL_DEPTH_TEST); // enable depth-testing
    glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
    glEnable (GL_CULL_FACE); // cull face
    glCullFace (GL_BACK); // cull back face
    glFrontFace (GL_CCW); // set counter-clock-wise vertex order to mean the front
    glClearColor (0.2, 0.2, 0.2, 1.0); // grey background to help spot mistakes
    glViewport (0, 0, g_gl_width, g_gl_height);

    /*-------------------------------RENDERING LOOP-------------------------------*/
    while (!glfwWindowShouldClose (g_window)) {
        // update timers
        static double previous_seconds = glfwGetTime ();
        double current_seconds = glfwGetTime ();
        double elapsed_seconds = current_seconds - previous_seconds;
        previous_seconds = current_seconds;
        _update_fps_counter (g_window);

        // wipe the drawing surface clear
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUseProgram (shader_programme);
        glBindVertexArray (vao);

        for (int i = 0; i < NUM_SPHERES; i++) {
            if (g_selected_sphere == i) {
                glUniform1f (blue_location, 1.0f);
            } else {
                glUniform1f (blue_location, 0.0f);
            }
            glUniformMatrix4fv (model_mat_location, 1, GL_FALSE, model_mats[i].m);
            glDrawArrays (GL_TRIANGLES, 0, g_point_count);
        }
        // update other events like input handling
        glfwPollEvents ();

        // control keys
        bool cam_moved = false;
        vec3 move (0.0, 0.0, 0.0);
        float cam_yaw = 0.0f; // y-rotation in degrees
        float cam_pitch = 0.0f;
        float cam_roll = 0.0;
        if (glfwGetKey (g_window, GLFW_KEY_A)) {
            move.v[0] -= cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (g_window, GLFW_KEY_D)) {
            move.v[0] += cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (g_window, GLFW_KEY_Q)) {
            move.v[1] += cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (g_window, GLFW_KEY_E)) {
            move.v[1] -= cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (g_window, GLFW_KEY_W)) {
            move.v[2] -= cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (g_window, GLFW_KEY_S)) {
            move.v[2] += cam_speed * elapsed_seconds;
            cam_moved = true;
        }
        if (glfwGetKey (g_window, GLFW_KEY_LEFT)) {
            cam_yaw += cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_yaw = quat_from_axis_deg (
                               cam_yaw, up.v[0], up.v[1], up.v[2]
                           );
            q = q_yaw * q;
        }
        if (glfwGetKey (g_window, GLFW_KEY_RIGHT)) {
            cam_yaw -= cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_yaw = quat_from_axis_deg (
                               cam_yaw, up.v[0], up.v[1], up.v[2]
                           );
            q = q_yaw * q;
        }
        if (glfwGetKey (g_window, GLFW_KEY_UP)) {
            cam_pitch += cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_pitch = quat_from_axis_deg (
                                 cam_pitch, rgt.v[0], rgt.v[1], rgt.v[2]
                             );
            q = q_pitch * q;
        }
        if (glfwGetKey (g_window, GLFW_KEY_DOWN)) {
            cam_pitch -= cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_pitch = quat_from_axis_deg (
                                 cam_pitch, rgt.v[0], rgt.v[1], rgt.v[2]
                             );
            q = q_pitch * q;
        }
        if (glfwGetKey (g_window, GLFW_KEY_Z)) {
            cam_roll -= cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_roll = quat_from_axis_deg (
                                cam_roll, fwd.v[0], fwd.v[1], fwd.v[2]
                            );
            q = q_roll * q;
        }
        if (glfwGetKey (g_window, GLFW_KEY_C)) {
            cam_roll += cam_heading_speed * elapsed_seconds;
            cam_moved = true;
            versor q_roll = quat_from_axis_deg (
                                cam_roll, fwd.v[0], fwd.v[1], fwd.v[2]
                            );
            q = q_roll * q;
        }
        // update view matrix
        if (cam_moved) {
            // re-calculate local axes so can move fwd in dir cam is pointing
            R = quat_to_mat4 (q);
            fwd = R * vec4 (0.0, 0.0, -1.0, 0.0);
            rgt = R * vec4 (1.0, 0.0, 0.0, 0.0);
            up = R * vec4 (0.0, 1.0, 0.0, 0.0);

            cam_pos = cam_pos + vec3 (fwd) * -move.v[2];
            cam_pos = cam_pos + vec3 (up) * move.v[1];
            cam_pos = cam_pos + vec3 (rgt) * move.v[0];
            mat4 T = translate (identity_mat4 (), vec3 (cam_pos));

            view_mat = inverse (R) * inverse (T);
            glUniformMatrix4fv (view_mat_location, 1, GL_FALSE, view_mat.m);
        }


        if (GLFW_PRESS == glfwGetKey (g_window, GLFW_KEY_ESCAPE)) {
            glfwSetWindowShouldClose (g_window, 1);
        }
        // put the stuff we've been drawing onto the display
        glfwSwapBuffers (g_window);
    }

    // close GL context and any other GLFW resources
    glfwTerminate();
    return 0;
}