Acme-MITHALDU-BleedingOpenGL
view release on metacpan or search on metacpan
pogl_matrix.xs view on Meta::CPAN
/* Last saved: Sun 06 Sep 2009 02:10:28 PM */
/* Copyright (c) 2015 Bob Free. All rights reserved.
* This program is free software; you can redistribute it and/or
* modify it under the same terms as Perl itself.
*/
/* OpenGL::Matrix */
#define IN_POGL_MATRIX_XS
#include <stdio.h>
#include <float.h>
#include "pgopogl.h"
#ifdef HAVE_GL
#include "gl_util.h"
#endif
#define PI (3.14159265359)
#define needs_2D(mat, function) \
if (mat->dimension_count != 2) \
{croak("OpenGL::Matrix::" function " requires a 2D matrix");}
#define needs_4x4(mat, function) \
if (mat->dimension_count != 2 || mat->dimensions[0] != 4 || mat->dimensions[1] != 4) \
{croak("OpenGL::Matrix::" function " requires a 4x4 matrix");}
static int get_index(OpenGL__Matrix mat, int col, int row)
{
int cols = mat->dimensions[0];
int rows = mat->dimensions[1];
return(row*cols + col);
}
static OpenGL__Matrix new_matrix(int cols, int rows)
{
int mat_len = sizeof(oga_struct);
OpenGL__Matrix mat = malloc(mat_len);
memset(mat, 0, mat_len);
int count = cols;
mat->dimension_count = 1;
if (rows)
{
count *= rows;
mat->dimension_count++;
}
mat->dimensions[0] = cols;
mat->dimensions[1] = rows;
mat->type_count = 1;
mat->item_count = count;
mat->total_types_width = gl_type_size(GL_FLOAT);
mat->data_length = mat->total_types_width * mat->item_count;
mat->types = malloc(sizeof(GLenum) * mat->type_count);
mat->type_offset = malloc(sizeof(GLint) * mat->type_count);
mat->data = malloc(mat->data_length);
mat->free_data = 1;
mat->type_offset[0] = 0;
mat->types[0] = GL_FLOAT;
return(mat);
}
static double vec_length(double* vec, int dimensions)
{
GLfloat ret = 0;
int i = 0;
for (; i<dimensions; i++) ret += pow(vec[i], 2);
return(pow(ret, .5));
}
static void fetch_arrayref(GLfloat* array, int maxlen, SV* sv, char* function, char* var)
{
if (!SvROK(sv))
{
croak("OpenGL::Matrix::%s %s is not a reference", function, var);
}
SV * tmpSV = (SV*)SvRV(sv);
if (SvTYPE(tmpSV) != SVt_PVAV)
{
croak("OpenGL::Matrix::%s %s is not an arrayref", function, var);
}
AV* arrayref = (AV*)tmpSV;
int len = av_len(arrayref)+1;
if (len > maxlen) len = maxlen;
int i = 0;
for (; i<len; i++)
{
SV** elem = av_fetch(arrayref, i, 0);
if (elem != NULL)
{
array[i] = (GLfloat)SvNV(*elem);
}
}
}
static void set_data_identity(GLfloat * data, int size)
{
int offset = 0;
int i = 0;
int j;
for (; i<size; i++)
{
for(j=0; j<size; j++)
{
data[offset++] = (i == j) ? 1.0 : 0.0;
}
}
}
static void set_data_frustrum(GLfloat * data,
GLfloat left, GLfloat right, GLfloat top, GLfloat bottom, GLfloat n, GLfloat f)
{
GLfloat width = right-left;
GLfloat height = bottom-top;
GLfloat depth = f-n;
data[0] = n*2.0/width;
data[1] = 0.0;
data[2] = 0.0;
data[3] = 0.0;
data[4] = 0.0;
pogl_matrix.xs view on Meta::CPAN
data[12] = 0.0;
data[13] = 0.0;
data[14] = -(f*n*2.0)/depth;
data[15] = 0.0;
}
static int inverse_lookup[] = {0,3,6,9,1,4,7,10,2,5,8,11};
MODULE = Acme::MITHALDU::BleedingOpenGL::Matrix PACKAGE = Acme::MITHALDU::BleedingOpenGL::Matrix
#ifdef IN_POGL_MATRIX_XS
#//# $mat = OpenGL::Matrix->new($cols, $rows[, (OGM)matrix]);
#//- Constructor for 2D Matrix OGM - populated with matrix if provided
OpenGL::Matrix
new(Class, cols, rows, ...)
GLsizei cols
GLsizei rows
CODE:
{
OpenGL__Matrix mat = new_matrix(cols, rows);
if (items > 3)
{
oga_struct * src_mat = INT2PTR(OpenGL__Array, SvIV((SV*)SvRV(ST(3))));
if (mat && src_mat->type_count == 1 && src_mat->types[0] == GL_FLOAT)
{
int src_offset;
int offset = 0;
if (src_mat->dimension_count == 2)
{
int src_cols = src_mat->dimensions[0];
int src_rows = src_mat->dimensions[1];
GLfloat * data = (GLfloat*)mat->data;
GLfloat * src_data = (GLfloat*)src_mat->data;
int i = 0;
int j;
for (; i < rows; i++)
{
src_offset = i * src_cols;
for (j = 0; j < cols; j++)
{
if (i < src_rows && j < src_cols)
{
data[offset] = src_data[src_offset++];
}
else
{
data[offset] = (i == j) ? 1.0 : 0.0;
}
offset++;
}
}
}
else if (mat->item_count <= src_mat->item_count)
{
memcpy(mat->data, src_mat->data, mat->data_length);
}
else
{
memcpy(mat->data, src_mat->data, src_mat->data_length);
int diff = mat->data_length - src_mat->data_length;
memset(mat->data+src_mat->data_length, 0.0, diff);
}
}
}
RETVAL = mat;
}
OUTPUT:
RETVAL
#//# $mat = OpenGL::Matrix->new_identity($size);
#//- Constructor for 2D Identity Matrix OGM
OpenGL::Matrix
new_identity(Class, size)
GLsizei size
CODE:
{
OpenGL__Matrix mat = new_matrix(size, size);
set_data_identity((GLfloat*)mat->data, size);
RETVAL = mat;
}
OUTPUT:
RETVAL
#//# $value = $mat->element($col, $row[, $new_value]);
#//- Get/Set the value of a 2D Matrix element
#//- When setting a new_value, returns the previous value
GLfloat
element(mat, col, row, ...)
OpenGL::Matrix mat
GLsizei col
GLsizei row
CODE:
{
needs_2D(mat, "element");
if (col >= mat->dimensions[0])
{
croak("OpenGL::Matrix::element col exceeds matrix width");
}
if (row >= mat->dimensions[1])
{
croak("OpenGL::Matrix::element row exceeds matrix height");
}
GLfloat * data = mat->data;
int index = get_index(mat, col, row);
RETVAL = data[index];
if (items > 3)
{
data[index] = (GLfloat)SvNV(ST(3));
}
}
OUTPUT:
RETVAL
#//# @row = $mat->row($row[, $arrayref]);
#//- Get/Set the value of a 2D Matrix row
#//- When setting new values, returns the previous row values
pogl_matrix.xs view on Meta::CPAN
GLfloat depth = f-n;
GLfloat * data = (GLfloat*)mat->data;
data[0] = 2/width;
data[1] = 0.0;
data[2] = 0.0;
data[3] = 0.0;
data[4] = 0.0;
data[5] = 2/height;
data[6] = 0.0;
data[7] = 0.0;
data[8] = 0.0;
data[9] = 0.0;
data[10] = -2/depth;
data[11] = 0.0;
data[12] = (right+left)/width;
data[13] = (bottom+top)/height;
data[14] = -(f+n)/depth;
data[15] = 1.0;
RETVAL = 0;
}
OUTPUT:
RETVAL
#//# $status = $mat->set_lookat($eye_vec, $at_vec, $up_vec);
#//- Set 4x4 LookAt Matrix; returns 0 if successful
GLint
set_lookat(mat, sv_eye, sv_at, sv_up)
OpenGL::Matrix mat
SV * sv_eye
SV * sv_at
SV * sv_up
CODE:
{
needs_4x4(mat, "set_lookat");
GLfloat eye_vec[3];
GLfloat at_vec[3];
GLfloat up_vec[3];
fetch_arrayref(eye_vec, 3, sv_eye, "set_lookat", "eye_vec");
fetch_arrayref(at_vec, 3, sv_at, "set_lookat", "at_vec");
fetch_arrayref(up_vec, 3, sv_up, "set_lookat", "up_vec");
GLfloat * data = (GLfloat*)mat->data;
double zaxis[] =
{
eye_vec[0] - at_vec[0],
eye_vec[1] - at_vec[1],
eye_vec[2] - at_vec[2]
};
if(!zaxis[0] && !zaxis[1] && !zaxis[2])
{
set_data_identity(data, 4);
}
else
{
double z = vec_length(zaxis, 3);
// Normalize distance
zaxis[0] /= z;
zaxis[1] /= z;
zaxis[2] /= z;
double xaxis[] =
{
up_vec[1]*zaxis[2] - up_vec[2]*zaxis[1],
up_vec[2]*zaxis[0] - up_vec[0]*zaxis[2],
up_vec[0]*zaxis[1] - up_vec[1]*zaxis[0],
};
double x = vec_length(xaxis, 3);
if (x)
{
// Normalize xaxis
xaxis[0] /= x;
xaxis[1] /= x;
xaxis[2] /= x;
}
else
{
xaxis[2] = 0;
}
double yaxis[] =
{
zaxis[1]*xaxis[2] - zaxis[2]*xaxis[1],
zaxis[2]*xaxis[0] - zaxis[0]*xaxis[2],
zaxis[0]*xaxis[1] - zaxis[1]*xaxis[0]
};
double y = vec_length(yaxis, 3);
if (y)
{
// Normalize yaxis
yaxis[0] /= y;
yaxis[1] /= y;
yaxis[2] /= y;
}
else
{
yaxis[0] = yaxis[1] = yaxis[2] = 0;
}
data[0] = xaxis[0];
data[1] = yaxis[0];
data[2] = zaxis[0];
data[3] = 0.0;
data[4] = xaxis[1];
data[5] = yaxis[1];
data[6] = zaxis[1];
data[7] = 0.0;
data[8] = xaxis[2];
data[9] = yaxis[2];
data[10] = zaxis[2];
data[11] = 0.0;
data[12] = -(xaxis[0]*eye_vec[0] + xaxis[1]*eye_vec[1] + xaxis[2]*eye_vec[2]);
data[13] = -(yaxis[0]*eye_vec[0] + yaxis[1]*eye_vec[1] + yaxis[2]*eye_vec[2]);
data[14] = -(zaxis[0]*eye_vec[0] + zaxis[1]*eye_vec[1] + zaxis[2]*eye_vec[2]);
data[15] = 1.0;
}
RETVAL = 0;
}
OUTPUT:
RETVAL
#//# $status = $mat->translate($x, $y, $z);
#//- Translate a 4x4 Matrix; returns 0 if successful
GLint
translate(mat, x, y, z)
OpenGL::Matrix mat
GLfloat x
GLfloat y
GLfloat z
CODE:
{
needs_4x4(mat, "translate");
GLfloat * data = (GLfloat*)mat->data;
int size = mat->dimensions[0];
int offset = size * (size-1);
data[offset++] += x;
data[offset++] += y;
data[offset] += z;
RETVAL = 0;
}
OUTPUT:
RETVAL
( run in 1.434 second using v1.01-cache-2.11-cpan-99c4e6809bf )