#include <stdio.h>
#include "pgopogl.h"
#ifdef HAVE_GL
#include "gl_util.h"
#endif
#ifdef HAVE_GLU
#include "glu_util.h"
#endif
GLint FBO_MAX = -1;
int
gpgpu_size(
void
)
{
#if defined(GL_ARB_texture_rectangle) && defined(GL_ARB_texture_float) && \
defined(GL_ARB_fragment_program) && defined(GL_EXT_framebuffer_object)
if
(FBO_MAX == -1)
{
if
(testProc(glProgramStringARB,
"glProgramStringARB"
) &&
testProc(glGenProgramsARB,
"glGenProgramsARB"
) &&
testProc(glBindProgramARB,
"glBindProgramARB"
) &&
testProc(glIsProgramARB,
"glIsProgramARB"
) &&
testProc(glProgramLocalParameter4fvARB,
"glProgramLocalParameter4fvARB"
) &&
testProc(glDeleteProgramsARB,
"glDeleteProgramsARB"
) &&
testProc(glGenFramebuffersEXT,
"glGenFramebuffersEXT"
) &&
testProc(glGenRenderbuffersEXT,
"glGenRenderbuffersEXT"
) &&
testProc(glBindFramebufferEXT,
"glBindFramebufferEXT"
) &&
testProc(glFramebufferTexture2DEXT,
"glFramebufferTexture2DEXT"
) &&
testProc(glBindRenderbufferEXT,
"glBindRenderbufferEXT"
) &&
testProc(glRenderbufferStorageEXT,
"glRenderbufferStorageEXT"
) &&
testProc(glFramebufferRenderbufferEXT,
"glFramebufferRenderbufferEXT"
) &&
testProc(glCheckFramebufferStatusEXT,
"glCheckFramebufferStatusEXT"
) &&
testProc(glDeleteRenderbuffersEXT,
"glDeleteRenderbuffersEXT"
) &&
testProc(glDeleteFramebuffersEXT,
"glDeleteFramebuffersEXT"
))
{
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT,&FBO_MAX);
}
else
{
FBO_MAX = 0;
}
}
return
(FBO_MAX);
#else
return
(0);
#endif
}
int
gpgpu_width(
int
len)
{
int
max = gpgpu_size();
if
(max && len && !(len%3))
{
int
count = len / 3;
int
w = (
int
)
sqrt
(count);
while
((w <= count) && (w <= max))
{
if
(!(count%w))
return
(w);
w++;
}
}
return
(0);
}
#ifdef GL_ARB_fragment_program
static
char
affine_prog[] =
"!!ARBfp1.0\n"
"PARAM affine[4] = {program.local[0..3]};\n"
"TEMP decal;\n"
"TEX decal, fragment.texcoord[0], texture[0], RECT;\n"
"MOV decal.w, 1.0;\n"
"DP4 result.color.x, decal, affine[0];\n"
"DP4 result.color.y, decal, affine[1];\n"
"DP4 result.color.z, decal, affine[2];\n"
"END\n"
;
void
enable_affine(oga_struct * oga)
{
if
(!oga)
return
;
if
(!oga->affine_handle)
{
glGenProgramsARB(1,&oga->affine_handle);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,oga->affine_handle);
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
GL_PROGRAM_FORMAT_ASCII_ARB,
strlen
(affine_prog),affine_prog);
if
(!glIsProgramARB(oga->affine_handle))
{
GLint errorPos;
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB,&errorPos);
if
(errorPos < 0) errorPos =
strlen
(affine_prog);
croak(
"Affine fragment program error\n%s"
,&affine_prog[errorPos]);
}
}
glEnable(GL_FRAGMENT_PROGRAM_ARB);
}
void
disable_affine(oga_struct * oga)
{
if
(!oga)
return
;
if
(oga->affine_handle) glDisable(GL_FRAGMENT_PROGRAM_ARB);
}
#endif
#ifdef GL_EXT_framebuffer_object
void
release_fbo(oga_struct * oga)
{
if
(oga->fbo_handle)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1,&oga->fbo_handle);
}
if
(oga->tex_handle[0] || oga->tex_handle[1])
{
glBindTexture(oga->target,0);
if
(oga->tex_handle[0]) glDeleteTextures(1,&oga->tex_handle[0]);
if
(oga->tex_handle[1]) glDeleteTextures(1,&oga->tex_handle[1]);
}
}
void
enable_fbo(oga_struct * oga,
int
w,
int
h, GLuint target,
GLuint pixel_type, GLuint pixel_format, GLuint element_size)
{
if
(!oga)
return
;
if
((oga->fbo_w != w) || (oga->fbo_h != h) ||
(oga->target != target) ||
(oga->pixel_type != pixel_type) ||
(oga->pixel_format != pixel_format) ||
(oga->element_size != element_size)) release_fbo(oga);
if
(!oga->fbo_handle)
{
GLenum status;
oga->fbo_w = w;
oga->fbo_h = h;
oga->target = target;
oga->pixel_type = pixel_type;
oga->pixel_format = pixel_format;
oga->element_size = element_size;
glGenTextures(2,oga->tex_handle);
glGenFramebuffersEXT(1,&oga->fbo_handle);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,oga->fbo_handle);
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,w,0,h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindTexture(target,oga->tex_handle[1]);
glTexParameteri(target,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(target,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(target,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(target,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexImage2D(target,0,pixel_type,w,h,0,
pixel_format,element_size,0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT,target,oga->tex_handle[1],0);
status = glCheckFramebufferStatusEXT(GL_RENDERBUFFER_EXT);
if
(status) croak(
"enable_fbo status: %04X\n"
,status);
}
else
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,oga->fbo_handle);
}
glBindTexture(target,oga->tex_handle[0]);
glTexImage2D(target,0,pixel_type,w,h,0,
pixel_format,element_size,oga->data);
glEnable(target);
glBindTexture(target,oga->tex_handle[0]);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
}
void
disable_fbo(oga_struct * oga)
{
if
(!oga)
return
;
if
(oga->fbo_handle)
{
glDisable(oga->target);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
}
}
#endif
#ifndef M_PI
#ifdef PI
#define M_PI PI
#else
#define M_PI 3.1415926535897932384626433832795
#endif
#endif
enum
{
RPN_NOP = 0,
RPN_PSH,
RPN_POP,
RPN_CNT,
RPN_IDX,
RPN_CLS,
RPN_COL,
RPN_RWS,
RPN_ROW,
RPN_SET,
RPN_GET,
RPN_STO,
RPN_LOD,
RPN_TST,
RPN_NOT,
RPN_EQU,
RPN_GRE,
RPN_LES,
RPN_END,
RPN_EIF,
RPN_ERW,
RPN_ERI,
RPN_RET,
RPN_RIF,
RPN_RRW,
RPN_RRI,
RPN_SUM,
RPN_AVG,
RPN_RND,
RPN_DUP,
RPN_SWP,
RPN_ABS,
RPN_NEG,
RPN_INC,
RPN_DEC,
RPN_ADD,
RPN_MUL,
RPN_DIV,
RPN_POW,
RPN_MOD,
RPN_MIN,
RPN_MAX,
RPN_SIN,
RPN_COS,
RPN_TAN,
RPN_AT2,
RPN_DMP,
RPN_FLR,
RPN_CGT,
RPN_CST,
RPN_RGT,
RPN_RST
};
enum
{
RPNF_CONTINUE = 0,
RPNF_END,
RPNF_ENDROW,
RPNF_RETURN,
RPNF_RETURNROW
};
struct
tag_rpn_op
{
int
op;
GLfloat value;
struct
tag_rpn_op * next;
};
typedef
struct
tag_rpn_op rpn_op;
struct
tag_rpn_stack
{
int
count;
int
max_count;
GLfloat * data;
rpn_op * ops;
};
typedef
struct
tag_rpn_stack rpn_stack;
struct
tag_rpn_context
{
int
rows;
int
cols;
int
oga_count;
oga_struct ** oga_list;
GLfloat * store;
rpn_stack ** stacks;
};
typedef
struct
tag_rpn_context rpn_context;
rpn_stack * rpn_parse(
int
size,
char
* string)
{
rpn_stack * stack =
malloc
(
sizeof
(rpn_stack));
rpn_op * op = NULL;
rpn_op * last = NULL;
char
* data = NULL;
memset
(stack,0,
sizeof
(rpn_stack));
if
(string && *string)
{
data =
malloc
(
strlen
(string)+1);
strcpy
(data,string);
string = data;
}
while
(string && *string)
{
rpn_op * cur = NULL;
char
* pos = string;
char
* end =
strchr
(pos,
','
);
int
len;
if
(end)
{
*end = 0;
string = end+1;
len = end - pos;
}
else
{
len =
strlen
(string);
string += len;
}
if
(!len)
continue
;
cur =
malloc
(
sizeof
(rpn_op));
memset
(cur,0,
sizeof
(rpn_op));
if
(last)
{
last->next = cur;
}
else
{
op = cur;
}
last = cur;
if
(len == 1)
{
switch
(*pos)
{
case
'!'
:
{
cur->op = RPN_NOT;
continue
;
}
case
'-'
:
{
cur->op = RPN_NEG;
continue
;
}
case
'+'
:
{
cur->op = RPN_ADD;
continue
;
}
case
'*'
:
{
cur->op = RPN_MUL;
continue
;
}
case
'/'
:
{
cur->op = RPN_DIV;
continue
;
}
case
'%'
:
{
cur->op = RPN_MOD;
continue
;
}
case
'='
:
{
cur->op = RPN_EQU;
size++;
continue
;
}
case
'>'
:
{
cur->op = RPN_GRE;
size++;
continue
;
}
case
'<'
:
{
cur->op = RPN_LES;
size++;
continue
;
}
case
'?'
:
{
cur->op = RPN_TST;
continue
;
}
}
}
if
(!
strcmp
(pos,
"pop"
))
{
cur->op = RPN_POP;
}
else
if
(!
strcmp
(pos,
"rand"
))
{
cur->op = RPN_RND;
size++;
}
else
if
(!
strcmp
(pos,
"dup"
))
{
cur->op = RPN_DUP;
size++;
}
else
if
(!
strcmp
(pos,
"swap"
))
{
cur->op = RPN_SWP;
}
else
if
(!
strcmp
(pos,
"set"
))
{
cur->op = RPN_SET;
}
else
if
(!
strcmp
(pos,
"get"
))
{
cur->op = RPN_GET;
size++;
}
else
if
(!
strcmp
(pos,
"store"
))
{
cur->op = RPN_STO;
}
else
if
(!
strcmp
(pos,
"load"
))
{
cur->op = RPN_LOD;
}
else
if
(!
strcmp
(pos,
"end"
))
{
cur->op = RPN_END;
}
else
if
(!
strcmp
(pos,
"endif"
))
{
cur->op = RPN_EIF;
}
else
if
(!
strcmp
(pos,
"endrow"
))
{
cur->op = RPN_ERW;
}
else
if
(!
strcmp
(pos,
"endrowif"
))
{
cur->op = RPN_ERI;
}
else
if
(!
strcmp
(pos,
"return"
))
{
cur->op = RPN_RET;
}
else
if
(!
strcmp
(pos,
"returnif"
))
{
cur->op = RPN_RIF;
}
else
if
(!
strcmp
(pos,
"returnrow"
))
{
cur->op = RPN_RRW;
}
else
if
(!
strcmp
(pos,
"returnrowif"
))
{
cur->op = RPN_RRI;
}
else
if
(!
strcmp
(pos,
"if"
))
{
cur->op = RPN_TST;
}
else
if
(!
strcmp
(pos,
"or"
))
{
cur->op = RPN_ADD;
}
else
if
(!
strcmp
(pos,
"and"
))
{
cur->op = RPN_MUL;
}
else
if
(!
strcmp
(pos,
"inc"
))
{
cur->op = RPN_INC;
}
else
if
(!
strcmp
(pos,
"dec"
))
{
cur->op = RPN_DEC;
}
else
if
(!
strcmp
(pos,
"sum"
))
{
cur->op = RPN_SUM;
}
else
if
(!
strcmp
(pos,
"avg"
))
{
cur->op = RPN_AVG;
}
else
if
(!
strcmp
(pos,
"abs"
))
{
cur->op = RPN_ABS;
}
else
if
(!
strcmp
(pos,
"power"
))
{
cur->op = RPN_POW;
}
else
if
(!
strcmp
(pos,
"min"
))
{
cur->op = RPN_MIN;
}
else
if
(!
strcmp
(pos,
"max"
))
{
cur->op = RPN_MAX;
}
else
if
(!
strcmp
(pos,
"sin"
))
{
cur->op = RPN_SIN;
}
else
if
(!
strcmp
(pos,
"cos"
))
{
cur->op = RPN_COS;
}
else
if
(!
strcmp
(pos,
"tan"
))
{
cur->op = RPN_TAN;
}
else
if
(!
strcmp
(pos,
"atan2"
))
{
cur->op = RPN_AT2;
}
else
if
(!
strcmp
(pos,
"count"
))
{
cur->op = RPN_CNT;
size++;
}
else
if
(!
strcmp
(pos,
"index"
))
{
cur->op = RPN_IDX;
size++;
}
else
if
(!
strcmp
(pos,
"columns"
))
{
cur->op = RPN_CLS;
size++;
}
else
if
(!
strcmp
(pos,
"column"
))
{
cur->op = RPN_COL;
size++;
}
else
if
(!
strcmp
(pos,
"rows"
))
{
cur->op = RPN_RWS;
size++;
}
else
if
(!
strcmp
(pos,
"row"
))
{
cur->op = RPN_ROW;
size++;
}
else
if
(!
strcmp
(pos,
"pi"
))
{
cur->op = RPN_PSH;
cur->value = (
float
)M_PI;
size++;
}
else
if
(!
strcmp
(pos,
"dump"
))
{
cur->op = RPN_DMP;
}
else
if
(!
strcmp
(pos,
"floor"
))
{
cur->op = RPN_FLR;
}
else
if
(!
strcmp
(pos,
"colget"
))
{
cur->op = RPN_CGT;
}
else
if
(!
strcmp
(pos,
"colset"
))
{
cur->op = RPN_CST;
}
else
if
(!
strcmp
(pos,
"rowget"
))
{
cur->op = RPN_RGT;
}
else
if
(!
strcmp
(pos,
"rowset"
))
{
cur->op = RPN_RST;
}
else
{
cur->op = RPN_PSH;
cur->value = (
float
)
atof
(pos);
size++;
}
}
if
(data)
free
(data);
stack->data =
malloc
(
sizeof
(GLfloat)*size);
stack->max_count = size;
stack->ops = op;
return
(stack);
}
rpn_context * rpn_init(
int
oga_count,oga_struct ** oga_list,
int
col_count,
char
** col_ops)
{
rpn_context * ctx = NULL;
int
elements = 0;
int
i,j;
if
(!oga_count) croak(
"Missing OGA count"
);
if
(!oga_list) croak(
"Missing OGA list"
);
if
(!col_count) croak(
"Missing column count"
);
for
(i=0; i<oga_count; i++)
{
if
(!oga_list[i]) croak(
"Missing OGA %d"
,i);
if
(!oga_list[i]->item_count) croak(
"Empty OGA %d"
,i);
if
(!i)
{
elements = oga_list[i]->item_count;
if
(elements % col_count) croak(
"Invalid OGA size for %d columns"
,col_count);
}
else
if
(elements != oga_list[i]->item_count)
{
croak(
"Invalid length in OGA %d"
,i);
}
for
(j=0; j<oga_list[i]->type_count; j++)
{
if
(oga_list[i]->types[j] != GL_FLOAT)
croak(
"Unsupported type in OGA %d"
,i);
}
}
ctx =
malloc
(
sizeof
(rpn_context));
if
(!ctx) croak(
"Unable to alloc rpn context"
);
ctx->store =
malloc
(
sizeof
(GLfloat) * col_count);
if
(!ctx->store) croak(
"Unable to alloc rpn store"
);
ctx->stacks =
malloc
(
sizeof
(rpn_stack *) * col_count);
if
(!ctx->stacks) croak(
"Unable to alloc rpn stacks"
);
ctx->cols =col_count;
ctx->rows = elements / col_count;
ctx->oga_count = oga_count;
ctx->oga_list = oga_list;
for
(i=0; i<col_count; i++)
ctx->stacks[i] = rpn_parse(oga_count,col_ops[i]);
return
(ctx);
}
void
rpn_delete_ops(rpn_op * ops)
{
if
(!ops)
return
;
rpn_delete_ops(ops->next);
free
(ops);
}
void
rpn_delete_stack(rpn_stack * stack)
{
if
(!stack)
return
;
rpn_delete_ops(stack->ops);
free
(stack->data);
free
(stack);
}
void
rpn_term(rpn_context * ctx)
{
if
(ctx)
{
int
i;
for
(i=0; i<ctx->cols; i++)
rpn_delete_stack(ctx->stacks[i]);
free
(ctx->stacks);
free
(ctx->store);
free
(ctx);
}
}
void
rpn_push(rpn_stack * stack, GLfloat value)
{
if
(stack){
if
(stack->count == stack->max_count)
croak(
"Trying to push past allocated rpn stack size: %d"
, stack->count);
stack->data[stack->count++] = value;
}
}
GLfloat rpn_pop(rpn_stack * stack)
{
GLfloat value = 0.0;
if
(stack && stack->count)
{
value = stack->data[--stack->count];
if
(!stack->count) rpn_push(stack,0.0);
}
return
(value);
}
void
rpn_dump(rpn_stack * stack,
int
row,
int
col,
float
reg)
{
if
(stack && stack->count)
{
int
i;
warn(
"-----------------(row: %d, col: %d)----\n"
, row, col);
warn(
"Register: %.7f\n"
, reg);
for
(i = stack->count - 1; i >= 0 ; i--)
warn(
"Stack %2d: %.7f\n"
, i, stack->data[stack->count - i - 1]);
}
else
{
warn(
"Empty Stack\n"
);
}
}
void
rpn_exec(rpn_context * ctx)
{
int
elements = ctx->rows * ctx->cols;
int
i,j,k,r = 0;
GLfloat v1,v2;
for
(i=0;i<ctx->rows;i++)
{
for
(j=0;j<ctx->cols;j++)
{
rpn_stack * stack = ctx->stacks[j];
int
flow = RPNF_CONTINUE;
rpn_op * ops;
if
(!stack || !stack->ops)
continue
;
stack->count = 0;
for
(k=ctx->oga_count-1;k>=0;k--)
rpn_push(stack,((GLfloat *)ctx->oga_list[k]->data)[r+j]);
ops = stack->ops;
while
(ops)
{
int
pos = stack->count - 1;
switch
(ops->op)
{
case
RPN_PSH:
{
rpn_push(stack,ops->value);
break
;
}
case
RPN_POP:
{
rpn_pop(stack);
break
;
}
case
RPN_CNT:
{
rpn_push(stack,(
float
)elements);
break
;
}
case
RPN_IDX:
{
rpn_push(stack,(
float
)r+j);
break
;
}
case
RPN_CLS:
{
rpn_push(stack,(
float
)ctx->cols);
break
;
}
case
RPN_COL:
{
rpn_push(stack,(
float
)j);
break
;
}
case
RPN_RWS:
{
rpn_push(stack,(
float
)ctx->rows);
break
;
}
case
RPN_ROW:
{
rpn_push(stack,(
float
)i);
break
;
}
case
RPN_SET:
{
ctx->store[j] = stack->data[pos];
break
;
}
case
RPN_GET:
{
rpn_push(stack,ctx->store[j]);
break
;
}
case
RPN_STO:
{
v1 = rpn_pop(stack);
k = ((
int
)v1) % ctx->oga_count;
if
(k < 0) k += ctx->oga_count;
memcpy
(ctx->store,&((GLfloat *)ctx->oga_list[k]->data)[r],
ctx->cols*
sizeof
(GLfloat));
break
;
}
case
RPN_CGT:
{
int
_col = (
int
)rpn_pop(stack);
if
(_col < 0) _col = 0;
if
(_col > ctx->cols-1) _col = ctx->cols-1;
rpn_push(stack,(
float
)((GLfloat *)ctx->oga_list[0]->data)[r+_col]);
break
;
}
case
RPN_CST:
{
int
_col = (
int
)rpn_pop(stack);
if
(_col < 0) _col = 0;
if
(_col > ctx->cols-1) _col = ctx->cols-1;
((GLfloat *)ctx->oga_list[0]->data)[r+_col] = stack->data[pos > 0 ? pos-1 : 0];
break
;
}
case
RPN_RGT:
{
int
_col = (
int
)rpn_pop(stack);
int
_row = (
int
)rpn_pop(stack);
if
(_row < 0) _row = 0;
if
(_row > ctx->rows-1) _row = ctx->rows-1;
if
(_col < 0) _col = 0;
if
(_col > ctx->cols-1) _col = ctx->cols-1;
rpn_push(stack,(
float
)((GLfloat *)ctx->oga_list[0]->data)[_row*ctx->cols+_col]);
break
;
}
case
RPN_RST:
{
int
_col = (
int
)rpn_pop(stack);
int
_row = (
int
)rpn_pop(stack);
if
(_row < 0) _row = 0;
if
(_row > ctx->rows-1) _row = ctx->rows-1;
if
(_col < 0) _col = 0;
if
(_col > ctx->cols-1) _col = ctx->cols-1;
((GLfloat *)ctx->oga_list[0]->data)[_row*ctx->cols+_col] = stack->data[pos > 1 ? pos-2 : 0];
break
;
}
case
RPN_FLR:
{
int
flr = (
int
)stack->data[pos];
stack->data[pos] = (
float
)flr;
break
;
}
case
RPN_LOD:
{
v1 = rpn_pop(stack);
k = ((
int
)v1) % ctx->oga_count;
if
(k < 0) k += ctx->oga_count;
memcpy
(&((GLfloat *)ctx->oga_list[k]->data)[r],ctx->store,
ctx->cols*
sizeof
(GLfloat));
break
;
}
case
RPN_TST:
{
v1 = rpn_pop(stack);
if
(v1 != 0.0)
{
rpn_pop(stack);
}
else
{
v1 = rpn_pop(stack);
rpn_pop(stack);
rpn_push(stack,v1);
}
break
;
}
case
RPN_NOT:
{
if
(!stack->count)
{
rpn_push(stack,1.0);
}
else
if
(stack->data[pos] == 0.0)
{
stack->data[pos] = 1.0;
}
else
{
stack->data[pos] = 0.0;
}
break
;
}
case
RPN_EQU:
{
v1 = (stack->count) ? rpn_pop(stack) : (
float
)0.0;
v2 = (stack->count) ? rpn_pop(stack) : (
float
)0.0;
rpn_push(stack,(
float
)((v1 == v2) ? 1.0 : 0.0));
break
;
}
case
RPN_GRE:
{
v1 = (stack->count) ? rpn_pop(stack) : (
float
)0.0;
v2 = (stack->count) ? rpn_pop(stack) : (
float
)0.0;
rpn_push(stack,(
float
)((v1 > v2) ? 1.0 : 0.0));
break
;
}
case
RPN_LES:
{
v1 = (stack->count) ? rpn_pop(stack) : (
float
)0.0;
v2 = (stack->count) ? rpn_pop(stack) : (
float
)0.0;
rpn_push(stack,(
float
)((v1 < v2) ? 1.0 : 0.0));
break
;
}
case
RPN_END:
{
flow = RPNF_END;
ops = 0;
continue
;
}
case
RPN_EIF:
{
v1 = rpn_pop(stack);
if
(v1 != 0.0)
{
flow = RPNF_END;
ops = 0;
continue
;
}
break
;
}
case
RPN_ERW:
{
flow = RPNF_ENDROW;
ops = 0;
continue
;
}
case
RPN_ERI:
{
v1 = rpn_pop(stack);
if
(v1 != 0.0)
{
flow = RPNF_ENDROW;
ops = 0;
continue
;
}
break
;
}
case
RPN_RET:
{
flow = RPNF_RETURN;
ops = 0;
continue
;
}
case
RPN_RIF:
{
v1 = rpn_pop(stack);
if
(v1 != 0.0)
{
flow = RPNF_RETURN;
ops = 0;
continue
;
}
break
;
}
case
RPN_RRW:
{
flow = RPNF_RETURNROW;
ops = 0;
continue
;
}
case
RPN_RRI:
{
v1 = rpn_pop(stack);
if
(v1 != 0.0)
{
flow = RPNF_RETURNROW;
ops = 0;
continue
;
}
break
;
}
case
RPN_RND:
{
rpn_push(stack,(
float
)(1.0*
rand
()/RAND_MAX));
break
;
}
case
RPN_DUP:
{
rpn_push(stack,stack->data[pos]);
break
;
}
case
RPN_SWP:
{
if
(pos >= 1)
{
v1 = stack->data[pos-1];
stack->data[pos-1] = stack->data[pos];
stack->data[pos] = v1;
}
break
;
}
case
RPN_ABS:
{
stack->data[pos] = (
float
)
fabs
(stack->data[pos]);
break
;
}
case
RPN_NEG:
{
stack->data[pos] *= (
float
)-1.0;
break
;
}
case
RPN_INC:
{
stack->data[pos] += (
float
)1.0;
break
;
}
case
RPN_DEC:
{
stack->data[pos] -= (
float
)1.0;
break
;
}
case
RPN_AVG:
case
RPN_SUM:
{
v1 = 0;
for
(pos=0; pos<stack->count; pos++)
v1 += stack->data[pos];
if
(ops->op == RPN_AVG) v1 /= stack->count;
stack->data[0] = v1;
stack->count = 1;
break
;
}
case
RPN_ADD:
{
if
(stack->count > 1)
{
v1 = rpn_pop(stack);
stack->data[--pos] += v1;
}
break
;
}
case
RPN_MUL:
{
if
(stack->count > 1)
{
v1 = rpn_pop(stack);
stack->data[--pos] *= v1;
}
break
;
}
case
RPN_DIV:
{
if
(stack->count > 1)
{
v1 = rpn_pop(stack);
if
(v1 != 0.0) stack->data[--pos] /= v1;
}
break
;
}
case
RPN_POW:
{
if
(stack->count > 1)
{
v1 = rpn_pop(stack);
pos--;
stack->data[pos] = (
float
)
pow
(stack->data[pos],v1);
}
break
;
}
case
RPN_MOD:
{
if
(stack->count > 1)
{
v1 = rpn_pop(stack);
pos--;
stack->data[pos] = (
float
)
fmod
(stack->data[pos],v1);
}
break
;
}
case
RPN_MIN:
{
if
(stack->count > 1)
{
v1 = rpn_pop(stack);
if
(stack->data[--pos] > v1)
stack->data[pos] = v1;
}
break
;
}
case
RPN_MAX:
{
if
(stack->count > 1)
{
v1 = rpn_pop(stack);
if
(stack->data[--pos] < v1)
stack->data[pos] = v1;
}
break
;
}
case
RPN_SIN:
{
stack->data[pos] = (
float
)
sin
(stack->data[pos]);
break
;
}
case
RPN_COS:
{
stack->data[pos] = (
float
)
cos
(stack->data[pos]);
break
;
}
case
RPN_TAN:
{
stack->data[pos] = (
float
)
tan
(stack->data[pos]);
break
;
}
case
RPN_AT2:
{
v2 = rpn_pop(stack);
v1 = rpn_pop(stack);
if
(v1 != 0.0 || v2 != 0.0)
rpn_push(stack,(
float
)
atan2
(v1,v2));
break
;
}
case
RPN_DMP:
{
rpn_dump(stack, i, j, ctx->store[j]);
break
;
}
case
RPN_NOP:
{
break
;
}
default
:
{
croak(
"Unknown RPN op: %d\n"
,ops->op);
}
}
ops = ops->next;
}
if
(!flow) {
((GLfloat *)ctx->oga_list[0]->data)[r+j] = rpn_pop(stack);
}
else
{
switch
(flow)
{
case
RPNF_RETURN:
{
((GLfloat *)ctx->oga_list[0]->data)[r+j] = rpn_pop(stack);
break
;
}
case
RPNF_RETURNROW:
{
((GLfloat *)ctx->oga_list[0]->data)[r+j] = rpn_pop(stack);
j = ctx->cols;
break
;
}
case
RPNF_ENDROW:
{
j = ctx->cols;
break
;
}
}
}
}
r += ctx->cols;
}
}
MODULE = OpenGL::Array PACKAGE = OpenGL::Array
#//# $oga = OpenGL::Array->new($count, @types);
#//- Constructor for multi-type OGA - unpopulated
OpenGL::Array
new
(Class, count, type, ...)
GLsizei count
GLenum type
CODE:
{
int
oga_len =
sizeof
(oga_struct);
oga_struct * oga =
malloc
(oga_len);
int
i,j;
memset
(oga,0,oga_len);
oga->dimension_count = 1;
oga->dimensions[0] = count;
oga->type_count = items - 2;
oga->item_count = count * (items - 2);
oga->types =
malloc
(
sizeof
(GLenum) * oga->type_count);
oga->type_offset =
malloc
(
sizeof
(GLint) * oga->type_count);
for
(i=0,j=0;i<oga->type_count;i++) {
oga->types[i] = SvIV(ST(i+2));
oga->type_offset[i] = j;
j += gl_type_size(oga->types[i]);
}
oga->total_types_width = j;
oga->data_length = oga->total_types_width *
count;
oga->data =
malloc
(oga->data_length);
memset
(oga->data,0,oga->data_length);
oga->free_data = 1;
RETVAL = oga;
}
OUTPUT:
RETVAL
#//# $oga = OpenGL::Array->new_list($type, @data);
#//- Constructor for mono-type OGA - populated
OpenGL::Array
new_list(Class, type, ...)
GLenum type
CODE:
{
int
oga_len =
sizeof
(oga_struct);
oga_struct * oga =
malloc
(oga_len);
int
count = items - 2;
memset
(oga,0,oga_len);
oga->dimension_count = 1;
oga->dimensions[0] = count;
oga->type_count = 1;
oga->item_count = count;
oga->total_types_width = gl_type_size(type);
oga->data_length = oga->total_types_width * oga->item_count;
oga->types =
malloc
(
sizeof
(GLenum) * oga->type_count);
oga->type_offset =
malloc
(
sizeof
(GLint) * oga->type_count);
oga->data =
malloc
(oga->data_length);
oga->free_data = 1;
oga->type_offset[0] = 0;
oga->types[0] = type;
SvItems(type,2,(GLuint)oga->item_count,oga->data);
RETVAL = oga;
}
OUTPUT:
RETVAL
#//# $oga = OpenGL::Array->new_scalar($type, (PACKED)data, $length);
#//- Constructor for mono-type OGA - populated by string
OpenGL::Array
new_scalar(Class, type, data, length)
GLenum type
SV * data
GLsizei length
CODE:
{
int
width = gl_type_size(type);
void
* data_s = EL(data, width*length);
int
oga_len =
sizeof
(oga_struct);
oga_struct * oga =
malloc
(oga_len);
int
count = length / width;
memset
(oga,0,oga_len);
oga->dimension_count = 1;
oga->dimensions[0] = count;
oga->type_count = 1;
oga->item_count = count;
oga->total_types_width = width;
oga->data_length = length;
oga->types =
malloc
(
sizeof
(GLenum) * oga->type_count);
oga->type_offset =
malloc
(
sizeof
(GLint) * oga->type_count);
oga->data =
malloc
(oga->data_length);
oga->free_data = 1;
oga->type_offset[0] = 0;
oga->types[0] = type;
memcpy
(oga->data,data_s,oga->data_length);
RETVAL = oga;
}
OUTPUT:
RETVAL
#//# $oga = OpenGL::Array->new_pointer($type, (CPTR)ptr, $elements);
#//- Constructor for mono-type OGA wrapper over a C pointer
OpenGL::Array
new_pointer(Class, type, ptr, elements)
GLenum type
void
* ptr
GLsizei elements
CODE:
{
int
width = gl_type_size(type);
int
oga_len =
sizeof
(oga_struct);
oga_struct * oga =
malloc
(
sizeof
(oga_struct));
memset
(oga,0,oga_len);
oga->dimension_count = 1;
oga->dimensions[0] = elements;
oga->type_count = 1;
oga->item_count = elements;
oga->types =
malloc
(
sizeof
(GLenum) * oga->type_count);
oga->type_offset =
malloc
(
sizeof
(GLint) * oga->type_count);
oga->types[0] = type;
oga->type_offset[0] = 0;
oga->total_types_width = width;
oga->data_length = elements * width;
oga->data = ptr;
oga->free_data = 0;
RETVAL = oga;
}
OUTPUT:
RETVAL
#//# $oga = OpenGL::Array->new_from_pointer((CPTR)ptr, $length);
#//- Constructor for GLubyte OGA wrapper over a C pointer
OpenGL::Array
new_from_pointer(Class, ptr, length)
void
* ptr
GLsizei length
CODE:
{
int
oga_len =
sizeof
(oga_struct);
oga_struct * oga =
malloc
(
sizeof
(oga_struct));
memset
(oga,0,oga_len);
oga->dimension_count = 1;
oga->dimensions[0] = length;
oga->type_count = 1;
oga->item_count = length;
oga->types =
malloc
(
sizeof
(GLenum) * oga->type_count);
oga->type_offset =
malloc
(
sizeof
(GLint) * oga->type_count);
oga->types[0] = GL_UNSIGNED_BYTE;
oga->type_offset[0] = 0;
oga->total_types_width = 1;
oga->data_length = oga->item_count;
oga->data = ptr;
oga->free_data = 0;
RETVAL = oga;
}
OUTPUT:
RETVAL
#//# $oga->update_pointer((CPTR)ptr);
#//- Replace OGA's C pointer - old one is not released
GLboolean
update_pointer(oga, ptr)
OpenGL::Array oga
void
* ptr
CODE:
{
RETVAL = (oga->data != ptr);
oga->data = ptr;
}
OUTPUT:
RETVAL
#//# $oga->bind($vboID);
#//- Bind a VBO to an OGA
void
bind(oga, bind)
OpenGL::Array oga
GLint bind
INIT:
#ifdef GL_ARB_vertex_buffer_object
loadProc(glBindBufferARB,
"glBindBufferARB"
);
#endif
CODE:
{
#ifdef GL_ARB_vertex_buffer_object
oga->bind = bind;
glBindBufferARB(GL_ARRAY_BUFFER_ARB,bind);
#else
croak(
"OpenGL::Array::bind requires GL_ARB_vertex_buffer_object"
);
#endif
}
#//# $vboID = $oga->bound();
#//- Return OGA's bound VBO ID
GLint
bound(oga)
OpenGL::Array oga
CODE:
RETVAL = oga->bind;
OUTPUT:
RETVAL
#//# $oga->calc([@(OGA)moreOGAs,]@rpnOPs);
#//- Execute RPN instructions on one or more OGAs
void
calc(...)
CODE:
{
rpn_context * ctx;
oga_struct ** oga_list;
int
oga_count = 0;
int
ops_count,i;
char
** ops;
for
(i=0; i<items; i++)
{
SV * sv = ST(i);
if
(sv == &PL_sv_undef ||
!sv_derived_from(sv,
"OpenGL::Array"
))
break
;
oga_count++;
}
if
(!oga_count) croak(
"Missing OGA parameters"
);
ops_count = items - oga_count;
oga_list =
malloc
(
sizeof
(oga_struct *) * oga_count);
if
(!oga_list) croak(
"Unable to alloc oga_list"
);
for
(i=0; i<oga_count; i++)
{
IV ref = SvIV((SV*)SvRV(ST(i)));
oga_list[i] = INT2PTR(OpenGL__Array,ref);
}
ops =
malloc
(
sizeof
(
char
*) * ops_count);
if
(!ops) croak(
"Unable to alloc ops"
);
for
(i=0;i<ops_count;i++)
{
SV * sv = ST(i+oga_count);
char
* op = (sv != &PL_sv_undef) ?
(
char
*)SvPV(sv,PL_na) :
""
;
ops[i] = op;
}
ctx = rpn_init(oga_count,oga_list,ops_count,ops);
rpn_exec(ctx);
rpn_term(ctx);
free
(ops);
free
(oga_list);
}
#//# $oga->assign($pos,@data);
#//- Set OGA values starting from offset
void
assign(oga, pos, ...)
OpenGL::Array oga
GLint pos
CODE:
{
int
i,j;
int
end;
GLenum t;
char
* offset;
i = pos;
end = i + items - 2;
if
(end > oga->item_count)
end = oga->item_count;
offset = ((
char
*)oga->data) +
(pos / oga->type_count * oga->total_types_width) +
oga->type_offset[pos % oga->type_count];
j = 2;
for
(;i<end;i++,j++) {
t = oga->types[i % oga->type_count];
switch
(t) {
#ifdef GL_VERSION_1_2
case
GL_UNSIGNED_BYTE_3_3_2:
case
GL_UNSIGNED_BYTE_2_3_3_REV:
(*(GLubyte*)offset) = (GLubyte)SvIV(ST(j));
offset +=
sizeof
(GLubyte);
break
;
case
GL_UNSIGNED_SHORT_5_6_5:
case
GL_UNSIGNED_SHORT_5_6_5_REV:
case
GL_UNSIGNED_SHORT_4_4_4_4:
case
GL_UNSIGNED_SHORT_4_4_4_4_REV:
case
GL_UNSIGNED_SHORT_5_5_5_1:
case
GL_UNSIGNED_SHORT_1_5_5_5_REV:
(*(GLushort*)offset) = (GLushort)SvIV(ST(j));
offset +=
sizeof
(GLushort);
break
;
case
GL_UNSIGNED_INT_8_8_8_8:
case
GL_UNSIGNED_INT_8_8_8_8_REV:
case
GL_UNSIGNED_INT_10_10_10_2:
case
GL_UNSIGNED_INT_2_10_10_10_REV:
(*(GLuint*)offset) = (GLuint)SvIV(ST(j));
offset +=
sizeof
(GLuint);
break
;
#endif
case
GL_UNSIGNED_BYTE:
case
GL_BITMAP:
(*(GLubyte*)offset) = (GLubyte)SvIV(ST(j));
offset +=
sizeof
(GLubyte);
break
;
case
GL_BYTE:
(*(GLbyte*)offset) = (GLbyte)SvIV(ST(j));
offset +=
sizeof
(GLbyte);
break
;
case
GL_UNSIGNED_SHORT:
(*(GLushort*)offset) = (GLushort)SvIV(ST(j));
offset +=
sizeof
(GLushort);
break
;
case
GL_SHORT:
(*(GLshort*)offset) = (GLshort)SvIV(ST(j));
offset +=
sizeof
(GLshort);
break
;
case
GL_UNSIGNED_INT:
(*(GLuint*)offset) = (GLuint)SvIV(ST(j));
offset +=
sizeof
(GLuint);
break
;
case
GL_INT:
(*(GLint*)offset) = (GLint)SvIV(ST(j));
offset +=
sizeof
(GLint);
break
;
case
GL_FLOAT:
(*(GLfloat*)offset) = (GLfloat)SvNV(ST(j));
offset +=
sizeof
(GLfloat);
break
;
case
GL_DOUBLE:
(*(GLdouble*)offset) = (GLdouble)SvNV(ST(j));
offset +=
sizeof
(GLdouble);
break
;
case
GL_2_BYTES:
{
unsigned
long
v = (unsigned
long
)SvIV(ST(j));
(*(GLubyte*)offset) = (GLubyte)(v >> 8);
offset++;
(*(GLubyte*)offset) = (GLubyte)v & 0xff;
offset++;
break
;
}
case
GL_3_BYTES:
{
unsigned
long
v = (unsigned
long
)SvIV(ST(j));
(*(GLubyte*)offset) = (GLubyte)(v >> 16)& 0xff;
offset++;
(*(GLubyte*)offset) = (GLubyte)(v >> 8) & 0xff;
offset++;
(*(GLubyte*)offset) = (GLubyte)(v >> 0) & 0xff;
offset++;
break
;
}
case
GL_4_BYTES:
{
unsigned
long
v = (unsigned
long
)SvIV(ST(j));
(*(GLubyte*)offset) = (GLubyte)(v >> 24)& 0xff;
offset++;
(*(GLubyte*)offset) = (GLubyte)(v >> 16)& 0xff;
offset++;
(*(GLubyte*)offset) = (GLubyte)(v >> 8) & 0xff;
offset++;
(*(GLubyte*)offset) = (GLubyte)(v >> 0) & 0xff;
offset++;
break
;
}
default
:
croak(
"unknown type"
);
}
}
}
#//# $oga->assign_data($pos,(PACKED)data);
#//- Set OGA values by string, starting from offset
void
assign_data(oga, pos, data)
OpenGL::Array oga
GLint pos
SV * data
CODE:
{
void
* offset;
void
* src;
STRLEN len;
offset = ((
char
*)oga->data) +
(pos / oga->type_count * oga->total_types_width) +
oga->type_offset[pos % oga->type_count];
src = SvPV(data, len);
memcpy
(offset, src, len);
}
#//# @data = $oga->retrieve($pos,$len);
#//- Get OGA data array, by offset and length
void
retrieve(oga, ...)
OpenGL::Array oga
PPCODE:
{
GLint pos = (items > 1) ? SvIV(ST(1)) : 0;
GLint len = (items > 2) ? SvIV(ST(2)) : (oga->item_count - pos);
char
* offset;
int
end = pos + len;
int
i;
offset = ((
char
*)oga->data) +
(pos / oga->type_count * oga->total_types_width) +
oga->type_offset[pos % oga->type_count];
if
(end > oga->item_count)
end = oga->item_count;
EXTEND(sp, end-pos);
i = pos;
for
(;i<end;i++) {
GLenum t = oga->types[i % oga->type_count];
switch
(t) {
#ifdef GL_VERSION_1_2
case
GL_UNSIGNED_BYTE_3_3_2:
case
GL_UNSIGNED_BYTE_2_3_3_REV:
PUSHs(sv_2mortal(newSViv( (*(GLubyte*)offset) )));
offset +=
sizeof
(GLubyte);
break
;
case
GL_UNSIGNED_SHORT_5_6_5:
case
GL_UNSIGNED_SHORT_5_6_5_REV:
case
GL_UNSIGNED_SHORT_4_4_4_4:
case
GL_UNSIGNED_SHORT_4_4_4_4_REV:
case
GL_UNSIGNED_SHORT_5_5_5_1:
case
GL_UNSIGNED_SHORT_1_5_5_5_REV:
PUSHs(sv_2mortal(newSViv( (*(GLushort*)offset) )));
offset +=
sizeof
(GLushort);
break
;
case
GL_UNSIGNED_INT_8_8_8_8:
case
GL_UNSIGNED_INT_8_8_8_8_REV:
case
GL_UNSIGNED_INT_10_10_10_2:
case
GL_UNSIGNED_INT_2_10_10_10_REV:
PUSHs(sv_2mortal(newSViv( (*(GLuint*)offset) )));
offset +=
sizeof
(GLuint);
break
;
#endif
case
GL_UNSIGNED_BYTE:
case
GL_BITMAP:
PUSHs(sv_2mortal(newSViv( (*(GLubyte*)offset) )));
offset +=
sizeof
(GLubyte);
break
;
case
GL_BYTE:
PUSHs(sv_2mortal(newSViv( (*(GLbyte*)offset) )));
offset +=
sizeof
(GLbyte);
break
;
case
GL_UNSIGNED_SHORT:
PUSHs(sv_2mortal(newSViv( (*(GLushort*)offset) )));
offset +=
sizeof
(GLushort);
break
;
case
GL_SHORT:
PUSHs(sv_2mortal(newSViv( (*(GLshort*)offset) )));
offset +=
sizeof
(GLshort);
break
;
case
GL_UNSIGNED_INT:
PUSHs(sv_2mortal(newSViv( (*(GLuint*)offset) )));
offset +=
sizeof
(GLuint);
break
;
case
GL_INT:
PUSHs(sv_2mortal(newSViv( (*(GLint*)offset) )));
offset +=
sizeof
(GLint);
break
;
case
GL_FLOAT:
PUSHs(sv_2mortal(newSVnv( (*(GLfloat*)offset) )));
offset +=
sizeof
(GLfloat);
break
;
case
GL_DOUBLE:
PUSHs(sv_2mortal(newSVnv( (*(GLdouble*)offset) )));
offset +=
sizeof
(GLdouble);
break
;
case
GL_2_BYTES:
case
GL_3_BYTES:
case
GL_4_BYTES:
default
:
croak(
"unknown type"
);
}
}
}
#//# $data = $oga->retrieve_data($pos,$len);
#//- Get OGA data as packed string, by offset and length
SV *
retrieve_data(oga, ...)
OpenGL::Array oga
CODE:
{
GLint pos = (items > 1) ? SvIV(ST(1)) : 0;
GLint len = (items > 2) ? SvIV(ST(2)) : (oga->item_count - pos);
void
* offset;
offset = ((
char
*)oga->data) +
(pos / oga->type_count * oga->total_types_width) +
oga->type_offset[pos % oga->type_count];
RETVAL = newSVpv((
char
*)offset, len);
}
OUTPUT:
RETVAL
#//# $count = $oga->elements();
#//- Get number of OGA elements
GLsizei
elements(oga)
OpenGL::Array oga
CODE:
RETVAL = oga->item_count;
OUTPUT:
RETVAL
#//# $len = $oga->length();
#//- Get size of OGA in bytes
GLsizei
length(oga)
OpenGL::Array oga
CODE:
RETVAL = oga->data_length;
OUTPUT:
RETVAL
#//# (CPTR)ptr = $oga->ptr();
#//- Get C pointer to OGA data
void
*
ptr(oga)
OpenGL::Array oga
CODE:
RETVAL = oga->data;
OUTPUT:
RETVAL
#//# (CPTR)ptr = $oga->offset($pos);
#//- Get C pointer to OGA data, by element offset
void
*
offset(oga, pos)
OpenGL::Array oga
GLint pos
CODE:
RETVAL = ((
char
*)oga->data) +
(pos / oga->type_count * oga->total_types_width) +
oga->type_offset[pos % oga->type_count];
OUTPUT:
RETVAL
#//# $oga->affine((OGA)matrix|@matrix|$scalar);
#//- Perform affine transform on an OGA
void
affine(oga, ...)
OpenGL::Array oga
CODE:
{
GLfloat * data = (GLfloat *)oga->data;
GLfloat * mat = NULL;
int
len = oga->item_count;
int
fbo_width = 0;
int
i,j,count,dim,cols;
SV * sv = ST(1);
int
free_mat = 0;
if
(sv != &PL_sv_undef && sv_derived_from(sv,
"OpenGL::Array"
))
{
IV ref = SvIV((SV*)SvRV(sv));
oga_struct *oga_mat = INT2PTR(OpenGL__Array,ref);
count = oga_mat->item_count;
for
(i=0;i<oga_mat->type_count;i++)
{
if
(oga_mat->types[i] != GL_FLOAT)
croak(
"Unsupported datatype in affine matrix"
);
}
mat = (GLfloat *)oga_mat->data;
}
else
{
count = items - 1;
free_mat = 1;
}
if
(!count) croak(
"No matrix values"
);
for
(i=0;i<oga->type_count;i++)
{
if
(oga->types[i] != GL_FLOAT)
croak(
"Unsupported datatype"
);
}
if
(count == 1)
{
GLfloat scalar = mat ? mat[0] : (GLfloat)SvNV(ST(1));
for
(i=0;i<len;i++) data[i] *= scalar;
XSRETURN_EMPTY;
}
dim = (
int
)
sqrt
(count);
if
(count != dim*dim) croak(
"Not a square matrix"
);
cols = dim - 1;
if
(len % cols)
croak(
"Matrix does not match array vector size"
);
if
(!mat)
{
mat =
malloc
(
sizeof
(GLfloat) * count);
for
(i=0; i<count; i++)
mat[i] = (GLfloat)SvNV(ST(i+1));
}
#if 0 /* Need to figure out why this is slower than CPU calcs */
fbo_width = gpgpu_width(len);
if
(dim == 4 && fbo_width)
{
GLuint target = GL_TEXTURE_RECTANGLE_ARB;
int
w = fbo_width;
int
h = len / (w*3);
enable_fbo(oga,w,h,target,GL_RGB32F_ARB,GL_RGB,GL_FLOAT);
enable_affine(oga);
for
(i=0;i<4;i++)
{
glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB,
i,&mat[i<<2]);
}
glBegin(GL_QUADS);
{
glTexCoord2i(0,0); glVertex2i(0,0);
glTexCoord2i(w,0); glVertex2i(w,0);
glTexCoord2i(w,h); glVertex2i(w,h);
glTexCoord2i(0,h); glVertex2i(0,h);
}
glEnd();
disable_affine(oga);
glReadPixels(0,0,w,h,GL_RGB,GL_FLOAT,oga->data);
disable_fbo(oga);
}
else
#endif
{
int
s =
sizeof
(GLfloat) * cols;
GLfloat *vec =
malloc
(s);
int
k,r;
for
(i=0; i < len; i+=cols)
{
for
(j=0,r=0; j<cols; j++,r+=dim)
{
vec[j] = 0.0;
for
(k=0; k<cols; k++)
{
vec[j] += data[i+k] * mat[r+k];
}
vec[j] += mat[r+cols];
}
memcpy
(data+i,vec,s);
}
free
(vec);
}
if
(free_mat)
free
(mat);
}
#//# @dimensions = $oga->get_dimensions();
#//- Get OGA data array, by offset and length
void
get_dimensions(oga)
OpenGL::Array oga
PPCODE:
{
int
end = oga->dimension_count;
int
i = 0;
EXTEND(sp, end);
for
(;i<end;i++) {
PUSHs(sv_2mortal(newSViv( oga->dimensions[i] )));
}
}
#// OGA Destructor
void
DESTROY(oga)
OpenGL::Array oga
CODE:
{
#if 0 /* Cleanup for GPU-based affine calcs */
#ifdef GL_ARB_fragment_program
if
(oga->affine_handle)
{
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
glDeleteProgramsARB(1,&oga->affine_handle);
}
#endif
#ifdef GL_EXT_framebuffer_object
release_fbo(oga);
#endif
#endif
#if 0
#ifdef GL_ARB_vertex_buffer_object
if
(oga->bind)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);
glDeleteBuffersARB(1,&oga->bind);
}
#endif
#endif
if
(oga->free_data)
{
memset
(oga->data,
'\0'
, oga->data_length);
free
(oga->data);
}
free
(oga->types);
free
(oga->type_offset);
free
(oga);
}
#//# glpHasGPGPU();
int
glpHasGPGPU()
CODE:
RETVAL = gpgpu_size();
OUTPUT:
RETVAL