/* Last saved: Sun 06 Sep 2009 02:10:28 PM */ /* Copyright (c) 1998 Kenneth Albanowski. All rights reserved. * Copyright (c) 2007 Bob Free. All rights reserved. * Copyright (c) 2009 Chris Marshall. All rights reserved. * This program is free software; you can redistribute it and/or * modify it under the same terms as Perl itself. */ /* OpenGL::Array */ #define IN_POGL_ARRAY_XS /* OpenGL RPN code */ #define IN_POGL_RPN_XS #include #include "pgopogl.h" #ifdef HAVE_GL #include "gl_util.h" #endif #ifdef HAVE_GLX #include "glx_util.h" #endif #ifdef HAVE_GLU #include "glu_util.h" #endif #ifdef IN_POGL_RPN_XS #ifndef M_PI #ifdef PI #define M_PI PI #else #define M_PI 3.1415926535897932384626433832795 #endif #endif #endif /* End IN_POGL_RPN_XS */ /* Note: this is caching procs once for all contexts */ /* !!! This should instead cache per context */ #ifdef HAVE_GL #if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_W32API)) #define loadProc(proc,name) \ { \ if (!proc) \ { \ proc = (void *)wglGetProcAddress(name); \ if (!proc) croak(name " is not supported by this renderer"); \ } \ } #define testProc(proc,name) ((proc) ? 1 : !!(proc = (void *)wglGetProcAddress(name))) #else #define loadProc(proc,name) #define testProc(proc,name) 1 #endif #endif #ifdef IN_POGL_RPN_XS /********************/ /* RPN Processor */ /********************/ /* RPN Ops */ 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, // Also OR RPN_MUL, // ALSO AND 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 }; /* RPN breaks */ enum { RPNF_CONTINUE = 0, RPNF_END, RPNF_ENDROW, RPNF_RETURN, RPNF_RETURNROW }; /* RPN OP link-list */ struct tag_rpn_op { int op; GLfloat value; struct tag_rpn_op * next; }; typedef struct tag_rpn_op rpn_op; /* RPN OP stack for a given column */ struct tag_rpn_stack { int count; GLfloat * data; rpn_op * ops; }; typedef struct tag_rpn_stack rpn_stack; /* RPN Object */ 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 Parser */ 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; /* Will destroy string, so make a copy */ memset(stack,0,sizeof(rpn_stack)); if (string && *string) { /* Assumes ASCII */ data = malloc(strlen(string)+1); strcpy(data,string); string = data; } /* OPs are comma-separated */ while (string && *string) { rpn_op * cur = NULL; char * pos = string; char * end = strchr(pos,','); int len; /* Grab op */ if (end) { *end = 0; string = end+1; len = end - pos; } else { len = strlen(string); string += len; } /* Empty op is a NOP */ if (!len) continue; /* Update linklist */ cur = malloc(sizeof(rpn_op)); memset(cur,0,sizeof(rpn_op)); if (last) { last->next = cur; } else { op = cur; } last = cur; /* Check for primitive OPs */ 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; continue; } case '>': { cur->op = RPN_GRE; continue; } case '<': { cur->op = RPN_LES; continue; } case '?': { cur->op = RPN_TST; continue; } } } /* Check for textual OPs */ 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; } /* Default to a numeric push */ else { cur->op = RPN_PSH; cur->value = (float)atof(pos); size++; } } /* release string copy */ if (data) free(data); stack->data = malloc(sizeof(GLfloat)*size); stack->ops = op; return(stack); } /* Instantiate an RPN Object */ 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"); /* Validate OGAs */ for (i=0; iitem_count) croak("Empty OGA %d",i); /* Check that all OGAs have the same dimension */ 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); } /* Only supporting GLfloat for now */ for (j=0; jtype_count; j++) { if (oga_list[i]->types[j] != GL_FLOAT) croak("Unsupported type in OGA %d",i); } } /* Alloc Object data */ ctx = malloc(sizeof(rpn_context)); if (!ctx) croak("Unable to alloc rpn context"); /* Alloc current row store */ ctx->store = malloc(sizeof(GLfloat) * col_count); if (!ctx->store) croak("Unable to alloc rpn store"); /* Alloc column stack array */ 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; /* Parse and populate column stacks */ for (i=0; istacks[i] = rpn_parse(oga_count,col_ops[i]); return(ctx); } /* Release OP link-list */ void rpn_delete_ops(rpn_op * ops) { if (!ops) return; rpn_delete_ops(ops->next); free(ops); } /* Release OPS stack */ void rpn_delete_stack(rpn_stack * stack) { if (!stack) return; rpn_delete_ops(stack->ops); free(stack->data); free(stack); } /* Release RPN Object */ void rpn_term(rpn_context * ctx) { if (ctx) { int i; for (i=0; icols; i++) rpn_delete_stack(ctx->stacks[i]); free(ctx->stacks); free(ctx->store); free(ctx); } } /* Push an RPN value on the stack */ void rpn_push(rpn_stack * stack, GLfloat value) { if (stack) stack->data[stack->count++] = value; } /* Pop an RPN value from the stack */ 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); } /* Dump out the current stack */ 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"); } } /* Execute RPN OPs stack */ void rpn_exec(rpn_context * ctx) { int elements = ctx->rows * ctx->cols; int i,j,k,r = 0; GLfloat v1,v2; for (i=0;irows;i++) { for (j=0;jcols;j++) { rpn_stack * stack = ctx->stacks[j]; int flow = RPNF_CONTINUE; /* or 0 */ rpn_op * ops; /* Skip for NOP columns */ if (!stack || !stack->ops) continue; stack->count = 0; /* Push oga data on stack - reverse order */ for (k=ctx->oga_count-1;k>=0;k--) rpn_push(stack,((GLfloat *)ctx->oga_list[k]->data)[r+j]); /* Process RPN ops */ ops = stack->ops; while (ops) { int pos = stack->count - 1; switch(ops->op) { case RPN_PSH: { //printf("RPN_PSH: %f\n",ops->value); rpn_push(stack,ops->value); break; } case RPN_POP: { //printf("RPN_POP\n"); rpn_pop(stack); break; } case RPN_CNT: { //printf("RPN_CNT: %f\n",elements); rpn_push(stack,(float)elements); break; } case RPN_IDX: { //printf("RPN_IDX: %f\n",r+j); rpn_push(stack,(float)r+j); break; } case RPN_CLS: { //printf("RPN_CLS: %f\n",ctx->cols); rpn_push(stack,(float)ctx->cols); break; } case RPN_COL: { //printf("RPN_COL: %f\n",j); rpn_push(stack,(float)j); break; } case RPN_RWS: { //printf("RPN_RWS: %f\n",ctx->rows); rpn_push(stack,(float)ctx->rows); break; } case RPN_ROW: { //printf("RPN_ROW: %f\n",i); rpn_push(stack,(float)i); break; } case RPN_SET: { //printf("RPN_SET %d: %f\n",j,stack->data[pos]); ctx->store[j] = stack->data[pos]; break; } case RPN_GET: { //printf("RPN_Get %d: %f\n",j,ctx->store[j]); rpn_push(stack,ctx->store[j]); break; } case RPN_STO: { //printf("RPN_STO row %d\n",r); 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: { //printf("RPN_CGT row %d\n",r); 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: { //printf("RPN_CST row %d\n",r); 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: { //printf("RPN_RGT row %d\n",r); 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: { //printf("RPN_RST row %d\n",r); 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: { //printf("RPN_FLR %d: %f\n",j,ctx->store[j]); int flr = (int)stack->data[pos]; stack->data[pos] = (float)flr; break; } case RPN_LOD: { //printf("RPN_LOD rwo %d\n",r); 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: { //printf("RPN_TST\n"); 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: { //printf("RPN_NOT\n"); 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: { //printf("RPN_EQU\n"); 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: { //printf("RPN_GRE\n"); 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: { //printf("RPN_LES\n"); 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: { //printf("RPN_END\n"); flow = RPNF_END; ops = 0; continue; } case RPN_EIF: { //printf("RPN_EIF\n"); v1 = rpn_pop(stack); if (v1 != 0.0) { flow = RPNF_END; ops = 0; continue; } break; } case RPN_ERW: { //printf("RPN_ERW\n"); flow = RPNF_ENDROW; ops = 0; continue; } case RPN_ERI: { //printf("RPN_ERI\n"); v1 = rpn_pop(stack); if (v1 != 0.0) { flow = RPNF_ENDROW; ops = 0; continue; } break; } case RPN_RET: { //printf("RPN_RET\n"); flow = RPNF_RETURN; ops = 0; continue; } case RPN_RIF: { //printf("RPN_RIF\n"); v1 = rpn_pop(stack); if (v1 != 0.0) { flow = RPNF_RETURN; ops = 0; continue; } break; } case RPN_RRW: { //printf("RPN_RRW\n"); flow = RPNF_RETURNROW; ops = 0; continue; } case RPN_RRI: { //printf("RPN_RRI\n"); v1 = rpn_pop(stack); if (v1 != 0.0) { flow = RPNF_RETURNROW; ops = 0; continue; } break; } case RPN_RND: { //printf("RPN_RND\n"); rpn_push(stack,(float)(1.0*rand()/RAND_MAX)); break; } case RPN_DUP: { //printf("RPN_DUP\n"); rpn_push(stack,stack->data[pos]); break; } case RPN_SWP: { //printf("RPN_SWP\n"); if (pos >= 1) { v1 = stack->data[pos-1]; stack->data[pos-1] = stack->data[pos]; stack->data[pos] = v1; } break; } case RPN_ABS: { //printf("RPN_ABS\n"); stack->data[pos] = (float)fabs(stack->data[pos]); break; } case RPN_NEG: { //printf("RPN_NEG\n"); stack->data[pos] *= (float)-1.0; break; } case RPN_INC: { //printf("RPN_INC\n"); stack->data[pos] += (float)1.0; break; } case RPN_DEC: { //printf("RPN_DEC\n"); stack->data[pos] -= (float)1.0; break; } case RPN_AVG: case RPN_SUM: { //printf("RPN_SUM/AVG\n"); v1 = 0; for(pos=0; poscount; pos++) v1 += stack->data[pos]; if (ops->op == RPN_AVG) v1 /= stack->count; stack->data[0] = v1; stack->count = 1; break; } case RPN_ADD: { //printf("RPN_ADD\n"); if (stack->count > 1) { v1 = rpn_pop(stack); stack->data[--pos] += v1; } break; } case RPN_MUL: { //printf("RPN_MUL\n"); if (stack->count > 1) { v1 = rpn_pop(stack); stack->data[--pos] *= v1; } break; } case RPN_DIV: { //printf("RPN_DIV\n"); if (stack->count > 1) { v1 = rpn_pop(stack); if (v1 != 0.0) stack->data[--pos] /= v1; } break; } case RPN_POW: { //printf("RPN_POW\n"); if (stack->count > 1) { v1 = rpn_pop(stack); stack->data[--pos] = (float)pow(stack->data[pos],v1); } break; } case RPN_MOD: { //printf("RPN_MOD\n"); if (stack->count > 1) { v1 = rpn_pop(stack); stack->data[--pos] = (float)fmod(stack->data[pos],v1); } break; } case RPN_MIN: { //printf("RPN_MIN\n"); if (stack->count > 1) { v1 = rpn_pop(stack); if (stack->data[--pos] > v1) stack->data[pos] = v1; } break; } case RPN_MAX: { //printf("RPN_MAX\n"); if (stack->count > 1) { v1 = rpn_pop(stack); if (stack->data[--pos] < v1) stack->data[pos] = v1; } break; } case RPN_SIN: { //printf("RPN_SIN\n"); stack->data[pos] = (float)sin(stack->data[pos]); break; } case RPN_COS: { //printf("RPN_COS\n"); stack->data[pos] = (float)cos(stack->data[pos]); break; } case RPN_TAN: { //printf("RPN_TAN\n"); stack->data[pos] = (float)tan(stack->data[pos]); break; } case RPN_AT2: { //printf("RPN_AT2\n"); 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: { //printf("RPN_DMP\n"); rpn_dump(stack, i, j, ctx->store[j]); break; } case RPN_NOP: { //printf("RPN_NOP\n"); break; } default: { croak("Unknown RPN op: %d\n",ops->op); } } ops = ops->next; } if (!flow) { /* RPNF_CONTINUE */ ((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; } } #endif /* End IN_POGL_RPN_XS */ MODULE = OpenGL::RPN PACKAGE = OpenGL::Array #ifdef IN_POGL_ARRAY_XS #//# $oga = OpenGL::Array->new($count, @types); #//- Contructor 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->type_count = items - 2; oga->item_count = count; oga->types = malloc(sizeof(GLenum) * oga->type_count); oga->type_offset = malloc(sizeof(GLint) * oga->type_count); for(i=0,j=0;itype_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->type_count-1) / oga->type_count); # vas is das? 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); #//- Contructor 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); memset(oga,0,oga_len); oga->type_count = 1; oga->item_count = items - 2; 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); #//- Contructor 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); memset(oga,0,oga_len); oga->type_count = 1; oga->item_count = length / width; 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); #//- Contructor 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->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); #//- Contructor 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->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; /* Determine number of OGAs passed in */ for (i=0; iassign($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; /* FIXME: is this char* conversion what is intended? */ offset = ((char*)oga->data) + (pos / oga->type_count * oga->total_types_width) + oga->type_offset[pos % oga->type_count]; j = 2; /* Handle multi-type OGAs */ for (;itypes[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 (;itypes[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; /* Get transform matrix OGA */ 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;itype_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"); /* Currently only support GLfloat */ for (i=0;itype_count;i++) { if (oga->types[i] != GL_FLOAT) croak("Unsupported datatype"); } /* Scalar Multiply */ if (count == 1) { GLfloat scalar = mat ? mat[0] : (GLfloat)SvNV(ST(1)); for (i=0;idata); disable_fbo(oga); } /* Use CPU to do transform */ else #endif { int s = sizeof(GLfloat) * cols; GLfloat *vec = malloc(s); int k,r; /* Iterate each data row */ for (i=0; i < len; i+=cols) { /* Iterate each result column */ for (j=0,r=0; jaffine_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) { /* To make sure dangling pointers will be obvious */ memset(oga->data, '\0', oga->data_length); free(oga->data); } free(oga->types); free(oga->type_offset); free(oga); } #endif /* End IN_POGL_ARRAY_XS */ MODULE = OpenGL::RPN PACKAGE = OpenGL ##################### GLU ######################### ############################## GLUT ######################### # /* This is assigned to GLX for now. The glp*() functions should be split out */