/* * Copyright (c) 2005-2007 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opengl.h" #include #include #ifdef HAVE_OPENGL #include #include "glview.h" #include AG_GLView * AG_GLViewNew(void *parent, Uint flags) { AG_GLView *glv; glv = Malloc(sizeof(AG_GLView)); AG_ObjectInit(glv, &agGLViewClass); glv->flags |= flags; if (flags & AG_GLVIEW_HFILL) { AG_ExpandHoriz(glv); } if (flags & AG_GLVIEW_VFILL) { AG_ExpandVert(glv); } AG_ObjectAttach(parent, glv); return (glv); } /* Initialize an OpenGL matrix to identity. GL must be locked. */ static void SetIdentity(GLfloat *M, GLenum which) { glMatrixMode(which); glPushMatrix(); glLoadIdentity(); glGetFloatv(which, M); glPopMatrix(); } static void WidgetMoved(AG_Event *event) { AG_GLView *glv = AG_SELF(); glv->flags |= AG_GLVIEW_RESHAPE; } static void mousebuttondown(AG_Event *event) { AG_GLView *glv = AG_SELF(); AG_WidgetFocus(glv); } static void Init(void *obj) { AG_GLView *glv = obj; WIDGET(glv)->flags |= AG_WIDGET_FOCUSABLE; if (!AG_GetBool(agConfig,"view.opengl")) AG_FatalError("AG_GLView requires OpenGL"); glv->wPre = 64; glv->hPre = 64; glv->flags = AG_GLVIEW_INIT_MATRICES; glv->draw_ev = NULL; glv->overlay_ev = NULL; glv->scale_ev = NULL; glv->keydown_ev = NULL; glv->btndown_ev = NULL; glv->keyup_ev = NULL; glv->btnup_ev = NULL; glv->motion_ev = NULL; AG_SetEvent(glv, "widget-moved", WidgetMoved, NULL); AG_SetEvent(glv, "window-mousebuttondown", mousebuttondown, NULL); } void AG_GLViewSizeHint(AG_GLView *glv, int w, int h) { AG_ObjectLock(glv); glv->wPre = w; glv->hPre = h; AG_ObjectUnlock(glv); } void AG_GLViewDrawFn(AG_GLView *glv, AG_EventFn fn, const char *fmt, ...) { AG_ObjectLock(glv); glv->draw_ev = AG_SetEvent(glv, NULL, fn, NULL); AG_EVENT_GET_ARGS(glv->draw_ev, fmt); AG_ObjectUnlock(glv); } void AG_GLViewOverlayFn(AG_GLView *glv, AG_EventFn fn, const char *fmt, ...) { AG_ObjectLock(glv); glv->overlay_ev = AG_SetEvent(glv, NULL, fn, NULL); AG_EVENT_GET_ARGS(glv->overlay_ev, fmt); AG_ObjectUnlock(glv); } void AG_GLViewScaleFn(AG_GLView *glv, AG_EventFn fn, const char *fmt, ...) { AG_ObjectLock(glv); glv->scale_ev = AG_SetEvent(glv, NULL, fn, NULL); AG_EVENT_GET_ARGS(glv->scale_ev, fmt); AG_ObjectUnlock(glv); } void AG_GLViewKeydownFn(AG_GLView *glv, AG_EventFn fn, const char *fmt, ...) { AG_ObjectLock(glv); glv->keydown_ev = AG_SetEvent(glv, "window-keydown", fn, NULL); AG_EVENT_GET_ARGS(glv->keydown_ev, fmt); AG_ObjectUnlock(glv); } void AG_GLViewKeyupFn(AG_GLView *glv, AG_EventFn fn, const char *fmt, ...) { AG_ObjectLock(glv); glv->keyup_ev = AG_SetEvent(glv, "window-keyup", fn, NULL); AG_EVENT_GET_ARGS(glv->keyup_ev, fmt); AG_ObjectUnlock(glv); } void AG_GLViewButtondownFn(AG_GLView *glv, AG_EventFn fn, const char *fmt, ...) { AG_ObjectLock(glv); glv->btndown_ev = AG_SetEvent(glv, "window-mousebuttondown", fn, NULL); AG_EVENT_GET_ARGS(glv->btndown_ev, fmt); AG_ObjectUnlock(glv); } void AG_GLViewButtonupFn(AG_GLView *glv, AG_EventFn fn, const char *fmt, ...) { AG_ObjectLock(glv); glv->btnup_ev = AG_SetEvent(glv, "window-mousebuttonup", fn, NULL); AG_EVENT_GET_ARGS(glv->btnup_ev, fmt); AG_ObjectUnlock(glv); } void AG_GLViewMotionFn(AG_GLView *glv, AG_EventFn fn, const char *fmt, ...) { AG_ObjectLock(glv); glv->motion_ev = AG_SetEvent(glv, "window-mousemotion", fn, NULL); AG_EVENT_GET_ARGS(glv->motion_ev, fmt); AG_ObjectUnlock(glv); } /* * Compute the projection matrix for the context and save it for later. * Called automatically when the widget is scaled or moved. */ void AG_GLViewReshape(AG_GLView *glv) { glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); if (glv->scale_ev != NULL) { glv->scale_ev->handler(glv->scale_ev); } glGetFloatv(GL_PROJECTION_MATRIX, glv->mProjection); glGetFloatv(GL_MODELVIEW_MATRIX, glv->mModelview); glGetFloatv(GL_TEXTURE_MATRIX, glv->mTexture); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_TEXTURE); glPopMatrix(); } void AG_GLViewSizeRequest(void *obj, AG_SizeReq *r) { r->w = 32; r->h = 32; } int AG_GLViewSizeAllocate(void *obj, const AG_SizeAlloc *a) { AG_GLView *glv = obj; if (a->w < 1 || a->h < 1) return (-1); glv->flags |= AG_GLVIEW_RESHAPE; return (0); } void AG_GLViewDraw(void *obj) { AG_GLView *glv = obj; if (glv->flags & AG_GLVIEW_INIT_MATRICES) { glv->flags &= ~(AG_GLVIEW_INIT_MATRICES); SetIdentity(glv->mProjection, GL_PROJECTION); SetIdentity(glv->mModelview, GL_MODELVIEW); SetIdentity(glv->mTexture, GL_TEXTURE); } if (glv->flags & AG_GLVIEW_RESHAPE) { glv->flags &= ~(AG_GLVIEW_RESHAPE); AG_GLViewReshape(glv); } glViewport(WIDGET(glv)->rView.x1, agView->h - WIDGET(glv)->rView.y2, WIDGET(glv)->w, WIDGET(glv)->h); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadMatrixf(glv->mTexture); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadMatrixf(glv->mProjection); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadMatrixf(glv->mModelview); glPushAttrib(GL_TRANSFORM_BIT); glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); if (glv->draw_ev != NULL) glv->draw_ev->handler(glv->draw_ev); glPopAttrib(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glViewport(0, 0, agView->w, agView->h); if (glv->overlay_ev != NULL) glv->overlay_ev->handler(glv->overlay_ev); } AG_WidgetClass agGLViewClass = { { "Agar(Widget:GLView)", sizeof(AG_GLView), { 0,0 }, Init, NULL, /* free */ NULL, /* destroy */ NULL, /* load */ NULL, /* save */ NULL /* edit */ }, AG_GLViewDraw, AG_GLViewSizeRequest, AG_GLViewSizeAllocate }; #endif /* HAVE_OPENGL */