/* Copyright (c) 1998 Kenneth Albanowski. All rights reserved. * This program is free software; you can redistribute it and/or * modify it under the same terms as Perl itself. */ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.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 HAVE_GLUT #include "glut_util.h" #endif /* Supported extensions: 2 GL_EXT_blend_color (missing spec) 3 GL_EXT_polygon_offset 4 GL_EXT_texture 10 GL_EXT_copy_texture 20 GL_EXT_texture_object 18 GL_EXT_cmyka 31 GL_EXT_misc_attribute 37 GL_EXT_blend_minmax (missing spec) 38 GL_EXT_blend_subtract (missing spec) 39 GL_EXT_blend_logic_op 44 GL_EXT_abgr 75 GLU_EXT_object_space_tess 79 GL_EXT_clip_volume_hint MESA_window_pos MESA_resize_buffers */ static int not_here(s) char *s; { croak("%s not implemented on this architecture", s); return -1; } /* GLUT on OS/2 PM runs callbacks from a secondary thread. This thread is not instrumented to run EMX CRTL functions. Basically, no Perl function may be run from this thread. We create a ternary thread via CRTL _beginthread() call, and communicate the requests to this thread via inter-thread communication (ITC). */ #ifndef __PM__ # define DO_perl_call_sv(handler, flag) perl_call_sv(handler, flag) # define ENSURE_callback_thread # define GLUT_PUSH_NEW_SV(sv) XPUSHs(sv_2mortal(newSVsv(sv))) # define GLUT_PUSH_NEW_IV(i) XPUSHs(sv_2mortal(newSViv(i))) # define GLUT_PUSH_NEW_U8(c) XPUSHs(sv_2mortal(newSViv((int)c))) # define GLUT_EXTEND_STACK(sp,n) # define GLUT_PUSHMARK(sp) PUSHMARK(sp) #else # define GLUT_PUSHMARK(sp) # include "sys/builtin.h" # include "sys/fmutex.h" # include "os2pm_X.h" # define DO_perl_call_sv(handler, flag) \ STMT_START { PUSHs(handler); \ PUTBACK; \ extend_by = 0; \ RUN_perl_call_sv(); \ } STMT_END # define GLUT_START_PUSHING 7 # define GLUT_PUSHING_IVP 17 # define GLUT_PUSHING_U8 27 # define GLUT_PUSHING_SV 37 # define GLUT_EXTEND_STACK(p,n) \ STMT_START { if (PL_stack_max - p < 2*(n)+4) { \ extend_by = 2*(n)+4; \ RUN_perl_call_sv(); \ } \ SPAGAIN; \ PUSHs((SV*)GLUT_START_PUSHING); \ } STMT_END # define GLUT_PUSH_NEW_SV(sv) (PUSHs(sv), PUSHs((SV*)GLUT_PUSHING_SV)) # define GLUT_PUSH_NEW_IV(i) (PUSHs((SV*)&i), PUSHs((SV*)GLUT_PUSHING_IVP)) # define GLUT_PUSH_NEW_U8(c) (PUSHs((SV*)(int)c), PUSHs((SV*)GLUT_PUSHING_U8)) _fmutex run_mutex, result_mutex; static int worker_started; static int extend_by; void RUN_perl_call_sv(void) { char *s = NULL; if (_fmutex_release(&run_mutex)) s = "Error unlocking the callback thread"; /* result_mutex is requested on entry! Block until looper finishes. */ else if (_fmutex_request(&result_mutex, _FMR_IGNINT)) s = "Error requesting the callback thread"; if (s) write(2, s, strlen(s)); return; } void callback_thread_looper(void *dummy) { while (1) { /* It is requested already! Wait until somebody requests a run */ if (_fmutex_request(&run_mutex, _FMR_IGNINT)) { warn("Error unlocking in the callback thread"); worker_started = 0; return; } if (extend_by) { /* Need to extend the stack */ dSP; EXTEND(sp, extend_by); } else { dSP; SV* handler = POPs; STRLEN n_a; SV **last = sp, **f; /* The rest is put on stack in a "raw" pointer form */ while (1) { switch ((IV)*sp) { case GLUT_START_PUSHING: goto start_found; break; case GLUT_PUSHING_IVP: case GLUT_PUSHING_SV: case GLUT_PUSHING_U8: break; default: croak("Panic: broken descriptor/down when ITC for Glut: %#lx", (unsigned long)*sp); break; } sp -= 2; } start_found: f = sp + 1; sp--; PUSHMARK(sp); while (f < last) { switch ((IV)f[1]) { case GLUT_PUSHING_IVP: PUSHs(sv_2mortal(newSViv(*(IV*)*f))); break; case GLUT_PUSHING_U8: PUSHs(sv_2mortal(newSViv((IV)*f))); break; case GLUT_PUSHING_SV: PUSHs(sv_2mortal(newSVsv(*f))); break; default: croak("Panic: broken descriptor/up when ITC for Glut: %#lx", (unsigned long)f[1]); break; } f += 2; } PUTBACK; perl_call_sv(handler, G_DISCARD|G_EVAL); if (SvTRUE(ERRSV)) fprintf(stderr, "Error in a GLUT Callback: %s", SvPV(ERRSV, n_a)); } if (_fmutex_release(&result_mutex)) { warn("Error in a callback thread"); worker_started = 0; return; } } } # define ENSURE_callback_thread \ if (!worker_started) \ start_callback_thread() void start_callback_thread() { unsigned long rc; if (worker_started) return; if ( CheckOSError(_fmutex_create(&run_mutex, 0)) || CheckOSError(_fmutex_create(&result_mutex, 0)) || CheckOSError(_fmutex_request(&run_mutex, _FMR_IGNINT)) || CheckOSError(_fmutex_request(&result_mutex, _FMR_IGNINT))) croak("Error creating semaphores"); worker_started = _beginthread(&callback_thread_looper, NULL, 8*1024*1024, NULL); if (worker_started == -1) { worker_started = 0; croak("Error creating callback thread"); } } #endif /* __PM__ */ #define i(test) if (strEQ(name, #test)) return newSViv((int)test); #define f(test) if (strEQ(name, #test)) return newSVnv((double)test); #ifdef __PM__ #endif static SV * neoconstant(char * name, int arg) { #include "gl_const.h" #include "glu_const.h" #include "glut_const.h" #include "glx_const.h" #include "glpm_const.h" ; return 0; } #undef i #undef f #ifdef HAVE_GLX # define HAVE_GLpc /* Perl interface */ # define nativeWindowId(d, w) (w) static Bool WaitForNotify(Display *d, XEvent *e, char *arg) { return (e->type == MapNotify) && (e->xmap.window == (Window)arg); } # define glpResizeWindow(s1,s2,w,d) XResizeWindow(d,w,s1,s2) # define glpMoveWindow(s1,s2,w,d) XMoveWindow(d,w,s1,s2) # define glpMoveResizeWindow(s1,s2,s3,s4,w,d) XMoveResizeWindow(d,w,s1,s2,s3,s4) #endif /* defined HAVE_GLX */ #ifdef __PM__ # define HAVE_GLpc /* Perl interface */ # define auxXWindow() (croak("Not implemented: auxXWindow"),0) HMQ hmq; AV *EventAv; unsigned long LastEventMask; /* XXXX Common for all the windows */ Display myDisplay; #else # define InitSys() #endif /* defined __PM__ */ #ifdef HAVE_GLpc # define NUM_ARG 7 Display *dpy; int dpy_open; XVisualInfo *vi; Colormap cmap; XSetWindowAttributes swa; Window win; GLXContext cx; static int default_attributes[] = { GLX_RGBA, /*GLX_DOUBLEBUFFER,*/ None }; #endif /* defined HAVE_GLpc */ #ifdef GLUT_API_VERSION static AV * glut_handlers = 0; static void set_glut_win_handler(int win, int type, SV * data) { SV ** h; AV * a; if (!glut_handlers) glut_handlers = newAV(); h = av_fetch(glut_handlers, win, FALSE); if (!h) { a = newAV(); av_store(glut_handlers, win, newRV_inc((SV*)a)); SvREFCNT_dec(a); } else if (!SvOK(*h) || !SvROK(*h)) croak("Unable to establish glut handler"); else a = (AV*)SvRV(*h); av_store(a, type, newRV_inc(data)); SvREFCNT_dec(data); } static SV * get_glut_win_handler(int win, int type) { SV ** h; if (!glut_handlers) croak("Unable to locate glut handler"); h = av_fetch(glut_handlers, win, FALSE); if (!h || !SvOK(*h) || !SvROK(*h)) croak("Unable to locate glut handler"); h = av_fetch((AV*)SvRV(*h), type, FALSE); if (!h || !SvOK(*h) || !SvROK(*h)) croak("Unable to locate glut handler"); return SvRV(*h); } static void destroy_glut_win_handlers(int win) { SV ** h; AV * a; if (!glut_handlers) return; h = av_fetch(glut_handlers, win, FALSE); if (!h || !SvOK(*h) || !SvROK(*h)) return; av_store(glut_handlers, win, newSVsv(&PL_sv_undef)); } static void destroy_glut_win_handler(int win, int type) { SV ** h; AV * a; if (!glut_handlers) glut_handlers = newAV(); h = av_fetch(glut_handlers, win, FALSE); if (!h || !SvOK(*h) || !SvROK(*h)) return; a = (AV*)SvRV(*h); av_store(a, type, newSVsv(&PL_sv_undef)); } #define begin_decl_gwh(type, params, nparam) \ \ static void generic_glut_ ## type ## _handler params \ { \ int win = glutGetWindow(); \ AV * handler_data = (AV*)get_glut_win_handler(win, HANDLE_GLUT_ ## type); \ SV * handler; \ int i; \ dSP; \ \ handler = *av_fetch(handler_data, 0, 0); \ \ GLUT_PUSHMARK(sp); \ GLUT_EXTEND_STACK(sp,av_len(handler_data)+nparam); \ for (i=1;i<=av_len(handler_data);i++) \ GLUT_PUSH_NEW_SV(*av_fetch(handler_data, i, 0)); #define end_decl_gwh() \ PUTBACK; \ DO_perl_call_sv(handler, G_DISCARD); \ } #define decl_gwh_xs(type) \ { \ int win = glutGetWindow(); \ \ if (!handler || !SvOK(handler)) { \ destroy_glut_win_handler(win, HANDLE_GLUT_ ## type); \ glut ## type ## Func(NULL); \ } else { \ AV * handler_data = newAV(); \ \ PackCallbackST(handler_data, 0); \ \ set_glut_win_handler(win, HANDLE_GLUT_ ## type, (SV*)handler_data); \ \ glut ## type ## Func(generic_glut_ ## type ## _handler); \ } \ ENSURE_callback_thread;} #define decl_gwh_xs_nullfail(type, fail) \ { \ int win = glutGetWindow(); \ \ if (!handler || !SvOK(handler)) { \ croak fail; \ } else { \ AV * handler_data = newAV(); \ \ PackCallbackST(handler_data, 0); \ \ set_glut_win_handler(win, HANDLE_GLUT_ ## type, (SV*)handler_data); \ \ glut ## type ## Func(generic_glut_ ## type ## _handler); \ } \ ENSURE_callback_thread;} #define decl_ggh_xs(type) \ { \ if (glut_ ## type ## _handler_data) \ SvREFCNT_dec(glut_ ## type ## _handler_data); \ \ if (!handler || !SvOK(handler)) { \ glut_ ## type ## _handler_data = 0; \ glut ## type ## Func(NULL); \ } else { \ AV * handler_data = newAV(); \ \ PackCallbackST(handler_data, 0); \ \ glut_ ## type ## _handler_data = handler_data; \ \ glut ## type ## Func(generic_glut_ ## type ## _handler);\ } \ ENSURE_callback_thread;} #define begin_decl_ggh(type, params, nparam) \ \ static AV * glut_ ## type ## _handler_data = 0; \ \ static void generic_glut_ ## type ## _handler params \ { \ AV * handler_data = glut_ ## type ## _handler_data; \ SV * handler; \ int i; \ dSP; \ \ handler = *av_fetch(handler_data, 0, 0); \ \ GLUT_PUSHMARK(sp); \ GLUT_EXTEND_STACK(sp,av_len(handler_data)+nparam); \ for (i=1;i<=av_len(handler_data);i++) \ GLUT_PUSH_NEW_SV(*av_fetch(handler_data, i, 0)); \ #define end_decl_ggh() \ PUTBACK; \ DO_perl_call_sv(handler, G_DISCARD); \ } enum { HANDLE_GLUT_Display, HANDLE_GLUT_OverlayDisplay, HANDLE_GLUT_Reshape, HANDLE_GLUT_Keyboard, HANDLE_GLUT_Mouse, HANDLE_GLUT_Motion, HANDLE_GLUT_PassiveMotion, HANDLE_GLUT_Entry, HANDLE_GLUT_Visibility, HANDLE_GLUT_Special, HANDLE_GLUT_SpaceballMotion, HANDLE_GLUT_SpaceballRotate, HANDLE_GLUT_SpaceballButton, HANDLE_GLUT_ButtonBox, HANDLE_GLUT_Dials, HANDLE_GLUT_TabletMotion, HANDLE_GLUT_TabletButton }; begin_decl_gwh(Display, (void), 0) end_decl_gwh() begin_decl_gwh(OverlayDisplay, (void), 0) end_decl_gwh() begin_decl_gwh(Reshape, (int width, int height), 2) GLUT_PUSH_NEW_IV(width); GLUT_PUSH_NEW_IV(height); end_decl_gwh() begin_decl_gwh(Keyboard, (unsigned char key, int width, int height), 3) GLUT_PUSH_NEW_U8(key); GLUT_PUSH_NEW_IV(width); GLUT_PUSH_NEW_IV(height); end_decl_gwh() begin_decl_gwh(Mouse, (int button, int state, int x, int y), 4) GLUT_PUSH_NEW_IV(button); GLUT_PUSH_NEW_IV(state); GLUT_PUSH_NEW_IV(x); GLUT_PUSH_NEW_IV(y); end_decl_gwh() begin_decl_gwh(PassiveMotion, (int x, int y), 2) GLUT_PUSH_NEW_IV(x); GLUT_PUSH_NEW_IV(y); end_decl_gwh() begin_decl_gwh(Motion, (int x, int y), 2) GLUT_PUSH_NEW_IV(x); GLUT_PUSH_NEW_IV(y); end_decl_gwh() begin_decl_gwh(Visibility, (int state), 1) GLUT_PUSH_NEW_IV(state); end_decl_gwh() begin_decl_gwh(Entry, (int state), 1) GLUT_PUSH_NEW_IV(state); end_decl_gwh() begin_decl_gwh(Special, (int key, int width, int height), 3) GLUT_PUSH_NEW_IV(key); GLUT_PUSH_NEW_IV(width); GLUT_PUSH_NEW_IV(height); end_decl_gwh() begin_decl_gwh(SpaceballMotion, (int x, int y, int z), 3) GLUT_PUSH_NEW_IV(x); GLUT_PUSH_NEW_IV(y); GLUT_PUSH_NEW_IV(z); end_decl_gwh() begin_decl_gwh(SpaceballRotate, (int x, int y, int z), 3) GLUT_PUSH_NEW_IV(x); GLUT_PUSH_NEW_IV(y); GLUT_PUSH_NEW_IV(z); end_decl_gwh() begin_decl_gwh(SpaceballButton, (int button, int state), 2) GLUT_PUSH_NEW_IV(button); GLUT_PUSH_NEW_IV(state); end_decl_gwh() begin_decl_gwh(ButtonBox, (int button, int state), 2) GLUT_PUSH_NEW_IV(button); GLUT_PUSH_NEW_IV(state); end_decl_gwh() begin_decl_gwh(Dials, (int dial, int value), 2) GLUT_PUSH_NEW_IV(dial); GLUT_PUSH_NEW_IV(value); end_decl_gwh() begin_decl_gwh(TabletMotion, (int x, int y), 2) GLUT_PUSH_NEW_IV(x); GLUT_PUSH_NEW_IV(y); end_decl_gwh() begin_decl_gwh(TabletButton, (int button, int state, int x, int y), 4) GLUT_PUSH_NEW_IV(button); GLUT_PUSH_NEW_IV(state); GLUT_PUSH_NEW_IV(x); GLUT_PUSH_NEW_IV(y); end_decl_gwh() begin_decl_ggh(Idle, (void), 0) end_decl_ggh() begin_decl_ggh(MenuStatus, (int status, int x, int y), 3) GLUT_PUSH_NEW_IV(status); GLUT_PUSH_NEW_IV(x); GLUT_PUSH_NEW_IV(y); end_decl_ggh() begin_decl_ggh(MenuState, (int status), 1) GLUT_PUSH_NEW_IV(status); end_decl_ggh() static void generic_glut_timer_handler(int value) { AV * handler_data = (AV*)value; SV * handler; int i; dSP; handler = *av_fetch(handler_data, 0, 0); GLUT_PUSHMARK(sp); GLUT_EXTEND_STACK(sp,av_len(handler_data)); for (i=1;i<=av_len(handler_data);i++) GLUT_PUSH_NEW_SV(*av_fetch(handler_data, i, 0)); PUTBACK; DO_perl_call_sv(handler, G_DISCARD); SvREFCNT_dec(handler_data); } static AV * glut_menu_handlers = 0; static void generic_glut_menu_handler(int value) { AV * handler_data; SV * handler; SV ** h; int i; dSP; h = av_fetch(glut_menu_handlers, glutGetMenu(), FALSE); if (!h || !SvOK(*h) || !SvROK(*h)) croak("Unable to locate menu handler"); handler_data = (AV*)SvRV(*h); handler = *av_fetch(handler_data, 0, 0); GLUT_PUSHMARK(sp); GLUT_EXTEND_STACK(sp,av_len(handler_data) + 1); for (i=1;i<=av_len(handler_data);i++) GLUT_PUSH_NEW_SV(*av_fetch(handler_data, i, 0)); GLUT_PUSH_NEW_IV(value); PUTBACK; DO_perl_call_sv(handler, G_DISCARD); } #define PackCallbackST(av, first) \ if (SvROK(ST(first)) && (SvTYPE(SvRV(ST(first))) == SVt_PVAV)) { \ int i; \ AV * x = (AV*)SvRV(ST(first)); \ for(i=0;i<=av_len(x);i++) { \ av_push(av, newSVsv(*av_fetch(x, i, 0))); \ } \ } else { \ int i; \ for(i=first;i type ## _callback \ , params) \ if (t->polygon_data_av) \ for (i=0; i<=av_len(t->polygon_data_av); i++) \ XPUSHs(sv_2mortal(newSVsv(*av_fetch(t->polygon_data_av, i, 0)))); #define end_tess_marshaller() \ end_void_specific_marshaller() begin_tess_marshaller(begin, (GLenum type, void * polygon_data)) XPUSHs(sv_2mortal(newSViv(type))); end_tess_marshaller() begin_tess_marshaller(end, (void * polygon_data)) end_tess_marshaller() begin_tess_marshaller(edgeFlag, (GLboolean flag, void * polygon_data)) XPUSHs(sv_2mortal(newSViv(flag))); end_tess_marshaller() begin_tess_marshaller(vertex, (void * vertex_data, void * polygon_data)) if (vertex_data) { AV * vd = (AV*)vertex_data; for (i=0; i<=av_len(vd); i++) XPUSHs(sv_2mortal(newSVsv(*av_fetch(vd, i, 0)))); } end_tess_marshaller() begin_tess_marshaller(error, (GLenum errno_, void * polygon_data)) XPUSHs(sv_2mortal(newSViv(errno_))); end_tess_marshaller() begin_tess_marshaller(combine, (GLdouble coords[3], void * vertex_data[4], GLfloat weight[4], void ** outd, void * polygon_data)) croak("combine tess marshaller needs FIXME (see OpenGL.xs)"); end_tess_marshaller() #endif typedef void * ptr; MODULE = OpenGL PACKAGE = OpenGL::Array OpenGL::Array new(Class, count, type, ...) GLsizei count GLenum type CODE: { oga_struct * oga = malloc(sizeof(oga_struct)); int i,j; 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); oga->data = malloc(oga->data_length); oga->free_data = 1; memset(oga->data, '\0', oga->data_length); RETVAL = oga; } OUTPUT: RETVAL OpenGL::Array new_from_pointer(Class, ptr, length) void * ptr GLsizei length CODE: { oga_struct * oga = malloc(sizeof(oga_struct)); int i,j; 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 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; 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) = 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) = 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) = SvIV(ST(j)); offset += sizeof(GLuint); break; #endif case GL_UNSIGNED_BYTE: case GL_BITMAP: case GL_BYTE: (*(GLubyte*)offset) = SvIV(ST(j)); offset += sizeof(GLubyte); break; case GL_UNSIGNED_SHORT: case GL_SHORT: (*(GLushort*)offset) = SvIV(ST(j)); offset += sizeof(GLushort); break; case GL_UNSIGNED_INT: case GL_INT: (*(GLuint*)offset) = SvIV(ST(j)); offset += sizeof(GLuint); break; case GL_FLOAT: (*(GLfloat*)offset) = SvNV(ST(j)); offset += sizeof(GLfloat); break; case GL_DOUBLE: (*(GLdouble*)offset) = SvNV(ST(j)); offset += sizeof(GLdouble); break; case GL_2_BYTES: { unsigned long v = SvIV(ST(j)); (*(GLubyte*)offset) = v >> 8; offset++; (*(GLubyte*)offset) = v & 0xff; offset++; break; } case GL_3_BYTES: { unsigned long v = SvIV(ST(j)); (*(GLubyte*)offset) = (v >> 16)& 0xff; offset++; (*(GLubyte*)offset) = (v >> 8) & 0xff; offset++; (*(GLubyte*)offset) = (v >> 0) & 0xff; offset++; break; } case GL_4_BYTES: { unsigned long v = SvIV(ST(j)); (*(GLubyte*)offset) = (v >> 24)& 0xff; offset++; (*(GLubyte*)offset) = (v >> 16)& 0xff; offset++; (*(GLubyte*)offset) = (v >> 8) & 0xff; offset++; (*(GLubyte*)offset) = (v >> 0) & 0xff; offset++; break; } default: croak("unknown type"); } } } 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); } void retrieve(oga, pos, len) OpenGL::Array oga GLint pos GLint len PPCODE: { 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: case GL_BYTE: PUSHs(sv_2mortal(newSViv( (*(GLubyte*)offset) ))); offset += sizeof(GLubyte); break; case GL_UNSIGNED_SHORT: case GL_SHORT: PUSHs(sv_2mortal(newSViv( (*(GLushort*)offset) ))); offset += sizeof(GLushort); break; case GL_UNSIGNED_INT: case GL_INT: PUSHs(sv_2mortal(newSViv( (*(GLuint*)offset) ))); offset += sizeof(GLuint); 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"); } } } SV * retrieve_data(oga, pos, len) OpenGL::Array oga GLint pos GLint len CODE: { 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 void * ptr(oga) OpenGL::Array oga CODE: RETVAL = oga->data; OUTPUT: RETVAL 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 void DESTROY(oga) OpenGL::Array oga CODE: { 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); } MODULE = OpenGL PACKAGE = OpenGL SV * constant(name,arg) char * name int arg CODE: { RETVAL = neoconstant(name, arg); if (!RETVAL) RETVAL = newSVsv(&PL_sv_undef); } OUTPUT: RETVAL int _have_gl() CODE: #ifdef HAVE_GL RETVAL = 1; #else RETVAL = 0; #endif OUTPUT: RETVAL int _have_glu() CODE: #ifdef HAVE_GLU RETVAL = 1; #else RETVAL = 0; #endif OUTPUT: RETVAL int _have_glut() CODE: #ifdef HAVE_GLUT RETVAL = 1; #else RETVAL = 0; #endif OUTPUT: RETVAL int _have_glx() CODE: #ifdef HAVE_GLX RETVAL = 1; #else RETVAL = 0; #endif OUTPUT: RETVAL int _have_glp() CODE: #ifdef HAVE_GLpc RETVAL = 1; #else RETVAL = 0; #endif OUTPUT: RETVAL #ifdef HAVE_GL # 1.0 void glAccum(op, value) GLenum op GLfloat value # 1.0 void glAlphaFunc(func, ref) GLenum func GLclampf ref #ifdef GL_VERSION_1_1 void glAreTexturesResident_s(n, textures, residences) GLsizei n SV * textures SV * residences CODE: { void * textures_s = EL(textures, sizeof(GLuint)*n); void * residences_s = EL(residences, sizeof(GLboolean)*n); glAreTexturesResident(n, textures_s, residences_s); } void glAreTexturesResident_c(n, textures, residences) GLsizei n void * textures void * residences CODE: glAreTexturesResident(n, textures, residences); # 1.1 void glAreTexturesResident_p(...) PPCODE: { GLsizei n = items; GLuint * textures = malloc(sizeof(GLuint) * (n+1)); GLboolean * residences = malloc(sizeof(GLboolean) * (n+1)); GLboolean result; int i; for (i=0;itriangulator); void gluEndPolygon(tess) PGLUtess * tess CODE: gluEndPolygon(tess->triangulator); void gluBeginSurface(nurb) GLUnurbsObj * nurb void gluEndSurface(nurb) GLUnurbsObj * nurb void gluBeginTrim(nurb) GLUnurbsObj * nurb void gluEndTrim(nurb) GLUnurbsObj * nurb GLint gluBuild1DMipmaps_s(target, internalformat, width, format, type, data) GLenum target GLuint internalformat GLsizei width GLenum format GLenum type SV * data CODE: { GLvoid * ptr = ELI(data, width, 1, format, type, gl_pixelbuffer_unpack); gluBuild1DMipmaps(target, internalformat, width, format, type, ptr); } GLint gluBuild2DMipmaps_s(target, internalformat, width, height, format, type, data) GLenum target GLuint internalformat GLsizei width GLsizei height GLenum format GLenum type SV * data CODE: { GLvoid * ptr = ELI(data, width, height, format, type, gl_pixelbuffer_unpack); gluBuild2DMipmaps(target, internalformat, width, height, format, type, ptr); } void gluCylinder(quad, base, top, height, slices, stacks) GLUquadricObj * quad GLdouble base GLdouble top GLdouble height GLint slices GLint stacks void gluDeleteNurbsRenderer(nurb) GLUnurbsObj * nurb void gluDeleteQuadric(quad) GLUquadricObj * quad void gluDeleteTess(tess) PGLUtess * tess CODE: { if (tess->triangulator) gluDeleteTess(tess->triangulator); #ifdef GLU_VERSION_1_2 if (tess->polygon_data_av) SvREFCNT_dec(tess->polygon_data_av); if (tess->begin_callback) SvREFCNT_dec(tess->begin_callback); if (tess->edgeFlag_callback) SvREFCNT_dec(tess->edgeFlag_callback); if (tess->vertex_callback) SvREFCNT_dec(tess->vertex_callback); if (tess->end_callback) SvREFCNT_dec(tess->end_callback); if (tess->error_callback) SvREFCNT_dec(tess->error_callback); if (tess->combine_callback) SvREFCNT_dec(tess->combine_callback); if (tess->vertex_datas) SvREFCNT_dec(tess->vertex_datas); #endif free(tess); } void gluDisk(quad, inner, outer, slices, loops) GLUquadricObj * quad GLdouble inner GLdouble outer GLint slices GLint loops char * gluErrorString(error) GLenum error CODE: RETVAL = (char*)gluErrorString(error); OUTPUT: RETVAL GLfloat gluGetNurbsProperty_p(nurb, property) GLUnurbsObj * nurb GLenum property CODE: { GLfloat param; gluGetNurbsProperty(nurb, property, ¶m); RETVAL = param; } OUTPUT: RETVAL #ifdef GLU_VERSION_1_1 char * gluGetString(name) GLenum name CODE: RETVAL = (char*)gluGetString(name); OUTPUT: RETVAL #endif void gluLoadSamplingMatrices_p(nurb, m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12,m13,m14,m15,m16, o1,o2,o3,o4,o5,o6,o7,o8,o9,o10,o11,o12,o13,o14,o15,o16, v1,v2,v3,v4) GLUnurbsObj * nurb CODE: { GLfloat m[16], p[16]; GLint v[4]; int i; for (i=0;i<16;i++) m[i] = SvIV(ST(i+1)); for (i=0;i<16;i++) p[i] = SvIV(ST(i+1+16)); for (i=0;i<4;i++) v[i] = SvIV(ST(i+1+16+16)); gluLoadSamplingMatrices(nurb, m, p, v); } void gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) GLdouble eyeX GLdouble eyeY GLdouble eyeZ GLdouble centerX GLdouble centerY GLdouble centerZ GLdouble upX GLdouble upY GLdouble upZ GLUnurbsObj * gluNewNurbsRenderer() GLUquadricObj * gluNewQuadric() PGLUtess * gluNewTess() CODE: { RETVAL = calloc(sizeof(PGLUtess), 1); RETVAL->triangulator = gluNewTess(); } OUTPUT: RETVAL void gluNextContour(tess, type) PGLUtess * tess GLenum type CODE: gluNextContour(tess->triangulator, type); void gluNurbsCurve_c(nurb, nknots, knot, stride, ctlarray, order, type) GLUnurbsObj * nurb GLint nknots void * knot GLint stride void * ctlarray GLint order GLenum type CODE: gluNurbsCurve(nurb, nknots, knot, stride, ctlarray, order, type); void gluNurbsSurface_c(nurb, sknot_count, sknot, tknot_count, tknot, s_stride, t_stride, ctrlarray, sorder, torder, type) GLUnurbsObj * nurb GLint sknot_count void * sknot GLint tknot_count void * tknot GLint s_stride GLint t_stride void * ctrlarray GLint sorder GLint torder GLenum type CODE: gluNurbsSurface(nurb, sknot_count, sknot, tknot_count, tknot, s_stride, t_stride, ctrlarray, sorder, torder, type); void gluOrtho2D(left, right, bottom, top) GLdouble left GLdouble right GLdouble bottom GLdouble top void gluPartialDisk(quad, inner, outer, slices, loops, start, sweep) GLUquadricObj* quad GLdouble inner GLdouble outer GLint slices GLint loops GLdouble start GLdouble sweep void gluPerspective(fovy, aspect, zNear, zFar) GLdouble fovy GLdouble aspect GLdouble zNear GLdouble zFar void gluPickMatrix_p(x, y, delX, delY, m1,m2,m3,m4) GLdouble x GLdouble y GLdouble delX GLdouble delY CODE: { GLint m[4]; int i; for (i=0;i<4;i++) m[i] = SvIV(ST(i+4)); gluPickMatrix(x, y, delX, delY, &m[0]); } void gluProject_p(objx, objy, objz, m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12,m13,m14,m15,m16, o1,o2,o3,o4,o5,o6,o7,o8,o9,o10,o11,o12,o13,o14,o15,o16, v1,v2,v3,v4) GLdouble objx GLdouble objy GLdouble objz PPCODE: { GLdouble m[16], p[16], winx, winy, winz; GLint v[4]; int i; for (i=0;i<16;i++) m[i] = SvIV(ST(i+3)); for (i=0;i<16;i++) p[i] = SvIV(ST(i+3+16)); for (i=0;i<4;i++) v[i] = SvIV(ST(i+3+16+16)); i = gluProject(objx, objy, objz, m, p, v, &winx, &winy, &winz); if (i) { EXTEND(sp, 3); PUSHs(sv_2mortal(newSVnv(winx))); PUSHs(sv_2mortal(newSVnv(winy))); PUSHs(sv_2mortal(newSVnv(winz))); } } void gluPwlCurve_c(nurb, count, data, stride, type) GLUnurbsObj * nurb GLint count void * data GLint stride GLenum type CODE: gluPwlCurve(nurb, count, data, stride, type); void gluQuadricDrawStyle(quad, draw) GLUquadricObj * quad GLenum draw void gluQuadricNormals(quad, normal) GLUquadricObj * quad GLenum normal void gluQuadricOrientation(quad, orientation) GLUquadricObj * quad GLenum orientation void gluQuadricTexture(quad, texture) GLUquadricObj * quad GLenum texture GLint gluScaleImage_s(format, wIn, hIn, typeIn, dataIn, wOut, hOut, typeOut, dataOut) GLenum format GLsizei wIn GLsizei hIn GLenum typeIn SV * dataIn GLsizei wOut GLsizei hOut GLenum typeOut SV * dataOut CODE: { GLvoid * inptr, * outptr; STRLEN discard; ELI(dataIn, wIn, hIn, format, typeIn, gl_pixelbuffer_unpack); ELI(dataOut, wOut, hOut, format, typeOut, gl_pixelbuffer_pack); inptr = SvPV(dataIn, discard); outptr = SvPV(dataOut, discard); RETVAL = gluScaleImage(format, wIn, hIn, typeIn, inptr, wOut, hOut, typeOut, outptr); } OUTPUT: RETVAL void gluSphere(quad, radius, slices, stacks) GLUquadricObj * quad GLdouble radius GLint slices GLint stacks #ifdef GLU_VERSION_1_2 GLdouble gluGetTessProperty_p(tess, property) PGLUtess * tess GLenum property CODE: { GLdouble param; gluGetTessProperty(tess->triangulator, property, ¶m); RETVAL = param; } OUTPUT: RETVAL #void #gluNurbsCallback_p(nurb, which, handler, ...) #void #gluNurbsCallbackDataEXT #void #gluQuadricCallback void gluTessBeginCountour(tess) PGLUtess * tess CODE: gluTessBeginContour(tess->triangulator); void gluTessEndContour(tess) PGLUtess * tess CODE: gluTessEndContour(tess->triangulator); void gluTessBeginPolygon(tess, ...) PGLUtess * tess CODE: { if (tess->polygon_data_av) { SvREFCNT_dec(tess->polygon_data_av); tess->polygon_data_av = 0; } if (items > 1) { tess->polygon_data_av = newAV(); PackCallbackST(tess->polygon_data_av, 1); } gluTessBeginPolygon(tess->triangulator, tess); } void gluTessEndPolygon(tess) PGLUtess * tess CODE: { if (tess->polygon_data_av) { SvREFCNT_dec(tess->polygon_data_av); tess->polygon_data_av = 0; } } void gluTessNormal(tess, valueX, valueY, valueZ) PGLUtess * tess GLdouble valueX GLdouble valueY GLdouble valueZ CODE: gluTessNormal(tess->triangulator, valueX, valueY, valueZ); void gluTessProperty(tess, which, data) PGLUtess * tess GLenum which GLdouble data CODE: gluTessProperty(tess->triangulator, which, data); void gluTessCallback(tess, which, ...) PGLUtess * tess GLenum which CODE: { switch (which) { case GLU_TESS_BEGIN: case GLU_TESS_BEGIN_DATA: if (tess->begin_callback) { SvREFCNT_dec(tess->begin_callback); tess->begin_callback = 0; } break; case GLU_TESS_END: case GLU_TESS_END_DATA: if (tess->end_callback) { SvREFCNT_dec(tess->end_callback); tess->end_callback = 0; } break; } if ((items > 3) && !SvOK(ST(2))) { AV * callback = newAV(); PackCallbackST(callback, 2); switch (which) { case GLU_TESS_BEGIN: case GLU_TESS_BEGIN_DATA: tess->begin_callback = callback; gluTessCallback(tess->triangulator, which, _s_marshal_glu_t_callback_begin); break; case GLU_TESS_END: case GLU_TESS_END_DATA: tess->end_callback = callback; gluTessCallback(tess->triangulator, which, _s_marshal_glu_t_callback_end); break; } } } #endif void gluTessVertex(tess, x, y, z, ...) PGLUtess * tess GLdouble x GLdouble y GLdouble z CODE: { AV * data = 0; GLdouble v[3]; v[0] = x; v[1] = y; v[2] = z; if (items > 4) { data = newAV(); PackCallbackST(data, 4); if (!tess->vertex_datas) tess->vertex_datas = newAV(); av_push(tess->vertex_datas, newRV_inc((SV*)data)); SvREFCNT_dec(data); } gluTessVertex(tess->triangulator, &v[0], (void*)data); } void gluUnProject_p(winx, winy, winz, m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12,m13,m14,m15,m16, o1,o2,o3,o4,o5,o6,o7,o8,o9,o10,o11,o12,o13,o14,o15,o16, v1,v2,v3,v4) GLdouble winx GLdouble winy GLdouble winz PPCODE: { GLdouble m[16], p[16], objx, objy, objz; GLint v[4]; int i; for (i=0;i<16;i++) m[i] = SvIV(ST(i+3)); for (i=0;i<16;i++) p[i] = SvIV(ST(i+3+16)); for (i=0;i<4;i++) v[i] = SvIV(ST(i+3+16+16)); i = gluUnProject(winx, winy, winz, m, p, v, &objx, &objy, &objz); if (i) { EXTEND(sp, 3); PUSHs(sv_2mortal(newSVnv(objx))); PUSHs(sv_2mortal(newSVnv(objy))); PUSHs(sv_2mortal(newSVnv(objz))); } } #endif ############################## GLUT ######################### #ifdef GLUT_API_VERSION # GLUT void glutInit() CODE: { int argc; char ** argv; AV * ARGV; SV * ARGV0; int i; argv = 0; ARGV = perl_get_av("ARGV", FALSE); ARGV0 = perl_get_sv("0", FALSE); argc = av_len(ARGV)+2; if (argc) { argv = malloc(sizeof(char*)*argc); argv[0] = SvPV(ARGV0, PL_na); for(i=0;i<=av_len(ARGV);i++) argv[i+1] = SvPV(*av_fetch(ARGV, i, 0), PL_na); } i = argc; glutInit(&argc, argv); while(argc= 3 void glutFullScreen() #endif void glutPopWindow() void glutPushWindow() void glutShowWindow() void glutHideWindow() void glutIconifyWindow() void glutSetWindowTitle(title) char * title void glutSetIconTitle(title) char * title #if GLUT_API_VERSION >= 3 void glutSetCursor(cursor) int cursor #endif # Overlays #if GLUT_API_VERSION >= 3 void glutEstablishOverlay() void glutUseLayer(layer) GLenum layer void glutRemoveOverlay() void glutPostOverlayRedisplay() void glutShowOverlay() void glutHideOverlay() #endif # Menus int glutCreateMenu(handler=0, ...) SV * handler CODE: { if (!handler || !SvOK(handler)) { croak("A handler must be specified"); } else { AV * handler_data = newAV(); PackCallbackST(handler_data, 0); RETVAL = glutCreateMenu(generic_glut_menu_handler); if (!glut_menu_handlers) glut_menu_handlers = newAV(); av_store(glut_menu_handlers, RETVAL, newRV_inc((SV*)handler_data)); SvREFCNT_dec(handler_data); } } OUTPUT: RETVAL void glutSetMenu(menu) int menu int glutGetMenu() void glutDestroyMenu(menu) int menu CODE: { glutDestroyMenu(menu); av_store(glut_menu_handlers, menu, newSVsv(&PL_sv_undef)); } void glutAddMenuEntry(name, value) char * name int value void glutAddSubMenu(name, menu) char * name int menu void glutChangeToMenuEntry(entry, name, value) int entry char * name int value void glutChangeToSubMenu(entry, name, menu) int entry char * name int menu void glutRemoveMenuItem(entry) int entry void glutAttachMenu(button) int button void glutDetachMenu(button) int button # Callbacks void glutDisplayFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs_nullfail(Display, ("Display function must be specified")) #if GLUT_API_VERSION >= 3 void glutOverlayDisplayFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(OverlayDisplay) #endif void glutReshapeFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(Reshape) void glutKeyboardFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(Keyboard) void glutMouseFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(Mouse) void glutMotionFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(Motion) void glutPassiveMotionFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(PassiveMotion) void glutVisibilityFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(Visibility) # OS/2 PM implementation calls itself v2, but does not support these functions # It is very hard to test for this, so we check for some other omission... #if !defined(GL_SRC_ALPHA_SATURATE) || defined(GL_CONSTANT_COLOR) void glutEntryFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(Entry) #endif #if GLUT_API_VERSION >= 2 void glutSpecialFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(Special) # OS/2 PM implementation calls itself v2, but does not support these functions # It is very hard to test for this, so we check for some other omission... # if !defined(GL_SRC_ALPHA_SATURATE) || defined(GL_CONSTANT_COLOR) void glutSpaceballMotionFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(SpaceballMotion) void glutSpaceballRotateFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(SpaceballRotate) void glutSpaceballButtonFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(SpaceballButton) void glutButtonBoxFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(ButtonBox) void glutDialsFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(Dials) void glutTabletMotionFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(TabletMotion) void glutTabletButtonFunc(handler=0, ...) SV * handler CODE: decl_gwh_xs(TabletButton) # endif #endif #if GLUT_API_VERSION >= 3 void glutMenuStatusFunc(handler=0, ...) SV * handler CODE: decl_ggh_xs(MenuStatus) #endif void glutMenuStateFunc(handler=0, ...) SV * handler CODE: decl_ggh_xs(MenuState) void glutIdleFunc(handler=0, ...) SV * handler CODE: decl_ggh_xs(Idle) void glutTimerFunc(msecs, handler=0, ...) unsigned int msecs SV * handler CODE: { if (!handler || !SvOK(handler)) { croak("A handler must be specified"); } else { AV * handler_data = newAV(); PackCallbackST(handler_data, 1); glutTimerFunc(msecs, generic_glut_timer_handler, (int)handler_data); } ENSURE_callback_thread;} # Colors void glutSetColor(cell, red, green, blue) int cell GLdouble red GLdouble green GLdouble blue GLfloat glutGetColor(cell, component) int cell int component void glutCopyColormap(win) int win # State int glutGet(state) GLenum state #if GLUT_API_VERSION >= 3 int glutLayerGet(info) GLenum info #endif int glutDeviceGet(info) GLenum info #if GLUT_API_VERSION >= 3 int glutGetModifiers() #endif #if GLUT_API_VERSION >= 2 int glutExtensionSupported(extension) char * extension #endif # Font void glutBitmapCharacter(font, character) void * font int character void glutStrokeCharacter(font, character) void * font int character # OS/2 PM implementation calls itself v2, but does not support these functions # It is very hard to test for this, so we check for some other omission... #if GLUT_API_VERSION >= 2 && (!defined(GL_SRC_ALPHA_SATURATE) || defined(GL_CONSTANT_COLOR)) int glutBitmapWidth(font, character) void * font int character int glutStrokeWidth(font, character) void * font int character #endif # Solids void glutSolidSphere(radius, slices, stacks) GLdouble radius GLint slices GLint stacks void glutWireSphere(radius, slices, stacks) GLdouble radius GLint slices GLint stacks void glutSolidCube(size) GLdouble size void glutWireCube(size) GLdouble size void glutSolidCone(base, height, slices, stacks) GLdouble base GLdouble height GLint slices GLint stacks void glutWireCone(base, height, slices, stacks) GLdouble base GLdouble height GLint slices GLint stacks void glutSolidTorus(innerRadius, outerRadius, nsides, rings) GLdouble innerRadius GLdouble outerRadius GLint nsides GLint rings void glutWireTorus(innerRadius, outerRadius, nsides, rings) GLdouble innerRadius GLdouble outerRadius GLint nsides GLint rings void glutSolidDodecahedron() void glutWireDodecahedron() void glutSolidOctahedron() void glutWireOctahedron() void glutSolidTetrahedron() void glutWireTetrahedron() void glutSolidIcosahedron() void glutWireIcosahedron() void glutSolidTeapot(size) GLdouble size void glutWireTeapot(size) GLdouble size #endif /* def GLUT_API_VERSION */ # /* The following material is directly copied from Stan Melax's original OpenGL-0.4 */ #ifdef __PM__ void morphPM() #endif #ifdef HAVE_GLpc /* GLX or __PM__ */ GLXDrawable glpcOpenWindow(x,y,w,h,pw,steal,event_mask, ...) int x int y int w int h int pw int steal long event_mask CODE: { XEvent event; Window pwin=(Window)pw; int *attributes = default_attributes; if(items>NUM_ARG){ int i; attributes = (int *)malloc((items-NUM_ARG+1)* sizeof(int)); for(i=NUM_ARG;iscreen), vi->visual, AllocNone); /* create a window */ swa.colormap = cmap; swa.border_pixel = 0; swa.event_mask = event_mask; #endif /* defined HAVE_GLX */ if(!pwin){pwin=RootWindow(dpy, vi->screen);} if (steal) win = nativeWindowId(dpy, pwin); /* What about depth/visual */ else win = XCreateWindow(dpy, pwin, x, y, w, h, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa); if(!win) croak("No Window"); XMapWindow(dpy, win); #ifndef HAVE_GLX /* On OS/2: cannot create a context before mapping something... */ /* create a GLX context */ cx = glXCreateContext(dpy, vi, 0, GL_TRUE); if(!cx) croak("No context!\n"); LastEventMask = event_mask; #else /* HAVE_GLX */ if((event_mask & StructureNotifyMask) && !steal) { XIfEvent(dpy, &event, WaitForNotify, (char*)win); } #endif /* HAVE_GLX */ /* connect the context to the window */ if (!glXMakeCurrent(dpy, win, cx)) croak("Non current"); /* clear the buffer */ glClearColor(0,0,0,1); RETVAL = win; } void * glpDisplay() CODE: /* get a connection */ if (!dpy_open) { dpy = XOpenDisplay(0); dpy_open = 1; } if (!dpy) croak("No display!"); RETVAL = dpy; void glpMoveResizeWindow(x, y, width, height, w=win, d=dpy) void* d GLXDrawable w int x int y unsigned int width unsigned int height void glpMoveWindow(x, y, w=win, d=dpy) void* d GLXDrawable w int x int y void glpResizeWindow(width, height, w=win, d=dpy) void* d GLXDrawable w unsigned int width unsigned int height # If glpOpenWindow was used then glXSwapBuffers should be called # without parameters (i.e. use the default parameters) void glXSwapBuffers(w=win,d=dpy) void * d GLXDrawable w CODE: { glXSwapBuffers(d,w); } int XPending(d=dpy) void * d CODE: { RETVAL = XPending(d); } OUTPUT: RETVAL void glpXNextEvent(d=dpy) void * d PPCODE: { XEvent event; char buf[10]; KeySym ks; XNextEvent(d,&event); switch(event.type) { case ConfigureNotify: EXTEND(sp,3); PUSHs(sv_2mortal(newSViv(event.type))); PUSHs(sv_2mortal(newSViv(event.xconfigure.width))); PUSHs(sv_2mortal(newSViv(event.xconfigure.height))); break; case KeyPress: case KeyRelease: EXTEND(sp,2); PUSHs(sv_2mortal(newSViv(event.type))); XLookupString(&event.xkey,buf,sizeof(buf),&ks,0); buf[0]=(char)ks;buf[1]='\0'; PUSHs(sv_2mortal(newSVpv(buf,1))); break; case ButtonPress: case ButtonRelease: EXTEND(sp,4); PUSHs(sv_2mortal(newSViv(event.type))); PUSHs(sv_2mortal(newSViv(event.xbutton.button))); PUSHs(sv_2mortal(newSViv(event.xbutton.x))); PUSHs(sv_2mortal(newSViv(event.xbutton.y))); break; case MotionNotify: EXTEND(sp,4); PUSHs(sv_2mortal(newSViv(event.type))); PUSHs(sv_2mortal(newSViv(event.xmotion.state))); PUSHs(sv_2mortal(newSViv(event.xmotion.x))); PUSHs(sv_2mortal(newSViv(event.xmotion.y))); break; case Expose: default: EXTEND(sp,1); PUSHs(sv_2mortal(newSViv(event.type))); break; } } void glpXQueryPointer(w=win,d=dpy) void * d GLXDrawable w PPCODE: { int x,y,rx,ry; Window r,c; unsigned int m; XQueryPointer(d,w,&r,&c,&rx,&ry,&x,&y,&m); EXTEND(sp,3); PUSHs(sv_2mortal(newSViv(x))); PUSHs(sv_2mortal(newSViv(y))); PUSHs(sv_2mortal(newSViv(m))); } #endif void glpReadTex(file) char * file CODE: { GLsizei w,h; int d,i; char buf[250]; unsigned char *image; FILE *fp; fp=fopen(file,"r"); if(!fp) croak("couldn't open file %s",file); fgets(buf,250,fp); /* P3 */ if (buf[0] != 'P' || buf[1] != '3') croak("Format is not P3 in file %s",file); fgets(buf,250,fp); while (buf[0] == '#' && fgets(buf,250,fp)) ; /* Empty */ if (2 != sscanf(buf,"%d%d",&w,&h)) croak("couldn't read image size from file %s",file); if (1 != fscanf(fp,"%d",&d)) croak("couldn't read image depth from file %s",file); if(d != 255) croak("image depth != 255 in file %s unsupported",file); if(w>10000 || h>10000) croak("suspicious size w=%d d=%d in file %s", w, d, file); New(1431, image, w*h*3, unsigned char); for(i=0;i