/* Height Field Viewer -- a GIMP plugin * Copyright (C) 1997 Michael Callahan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include "libgimp/gimp.h" /* #define USE_TRIANGLE_STRIPS */ #define HZMAX 80 #define DISTANCE 30 #define HXSCALE(x) (256.0/(x) * 30.0) #define HYSCALE(x) (256.0/(x) * 30.0) #define WINDOW_WIDTH 400 #define WINDOW_HEIGHT 300 int iMAX(int a, int b) { if (b > a) return b; return a; } int iMIN(int a, int b) { if (b < a) return b; return a; } typedef struct hfield_t_ hfield_t; typedef struct hfield_data_t_ hfield_data_t; struct hfield_data_t_ { GLfloat h; GLfloat r; GLfloat g; GLfloat b; }; struct hfield_t_ { int sizex; int sizey; int distance; hfield_data_t *data; }; static hfield_t heightfield[256]; static int heightfield_count = 0; static GLfloat spin_z = 0.0; static GLfloat position_x = 0.0; static GLfloat position_y = 0.0; static GLfloat velocity = 0.0; /* Declare local functions. */ static void query (void); static void run (char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals); static void heightfield_init(hfield_t *hfield, GimpDrawable *drawable); static void heightfield_main(); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN () static void query () { static GimpParamDef args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, { GIMP_PDB_IMAGE, "image", "Input image (unused)" }, { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }, }; static GimpParamDef *return_vals = NULL; static int nargs = sizeof (args) / sizeof (args[0]); static int nreturn_vals = 0; gimp_install_procedure ("plug_in_heightview", "Display the contents of the specified drawable as an interactive height field", "This function displays the contents of the specified drawable as an interactive height field.", "Michael Callahan", "Michael Callahan", "1997", "/Filters/Render/Height Field Viewer", "RGB*", GIMP_PLUGIN, nargs, nreturn_vals, args, return_vals); } static void run (char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; GimpDrawable *drawable; GimpRunModeType run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; run_mode = param[0].data.d_int32; /* Get the specified drawable */ drawable = gimp_drawable_get (param[2].data.d_drawable); /* Make sure that the drawable is gray or RGB color */ if (gimp_drawable_is_rgb (drawable->id)) { gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1)); heightfield_init(&heightfield[0], drawable); heightfield_count = 1; heightfield_main(); } else { /* gimp_message ("blur: cannot operate on indexed color images"); */ status = GIMP_PDB_EXECUTION_ERROR; } *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; } static void heightfield_init(hfield_t *hfield, GimpDrawable *drawable) { GimpPixelRgn srcPR; hfield_data_t *h; int i, j; guchar buf[8]; hfield->sizex = drawable->width; hfield->sizey = drawable->height; hfield->distance = DISTANCE; hfield->data = malloc(sizeof(hfield_data_t) * hfield->sizex * hfield->sizey); gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, hfield->sizex, hfield->sizey, FALSE, FALSE); h = hfield->data; for (j=0; jsizey; j++) { for (i=0; isizex; i++) { gimp_pixel_rgn_get_row(&srcPR, buf, i, j, 1); h->r = buf[0] / 255.0; h->g = buf[1] / 255.0; h->b = buf[2] / 255.0; h->h = (h->r + h->g + h->b) / 3.0 * HZMAX; h++; } } } #ifdef USE_TRIANGLE_STRIPS static void draw_strip(hfield_t *a, hfield_t *b, int len, float ay, float by, float xscale) { int i; glBegin(GL_TRIANGLE_STRIP); for (i=0; isizex); GLdouble yscale = HYSCALE(hfield->sizey); int posy = hfield->sizey/2 + (int)(position_y/yscale); int startny = iMAX(0, posy - near); int endny = iMIN(hfield->sizey-1, posy + near); int startfy = iMAX(0, posy - far); int endfy = iMIN(hfield->sizey-1, posy + far); int posx = hfield->sizex/2 + (int)(position_x/xscale); int startnx = iMAX(0, posx - near); int endnx = iMIN(hfield->sizex-1, posx + near); int startfx = iMAX(0, posx - far); int endfx = iMIN(hfield->sizex-1, posx + far); for (j=startfy; jdata[(j+0)*hfield->sizex]; b = &hfield->data[(j+1)*hfield->sizex]; if (j < startny || j >= endny) { draw_strip(a, b, startfx, endfx, (j+0)*yscale, (j+1)*yscale, xscale); } else { draw_strip(a, b, startfx, startnx, j*yscale, (j+1)*yscale, xscale); draw_strip(a, b, endnx, endfx, j*yscale, (j+1)*yscale, xscale); } } } static void init() { glClearColor(0.8, 0.6, 0.6, 0.0); glShadeModel(GL_SMOOTH); glDisable(GL_CULL_FACE); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); } static void display() { int i; GLdouble atx, aty; GLdouble maxx, maxy; glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix(); /* glRotatef(90.0, 0.0, 0.0, 1.0); */ /* glRotatef(90.0, 0.0, 1.0, 0.0); */ /* glRotatef(90.0, 1.0, 0.0, 0.0); */ /* glRotatef(90.0, 0.0, 0.0, 1.0); */ /* glRotatef(180.0, 0.0, 0.0, 1.0); */ /* glRotatef(90.0, 1.0, 0.0, 0.0); */ position_x += sin(spin_z*M_PI/180.0) * velocity; position_y += cos(spin_z*M_PI/180.0) * velocity; maxx = heightfield[0].sizex * HXSCALE(heightfield[0].sizex) / 2.0; maxy = heightfield[0].sizey * HYSCALE(heightfield[0].sizey) / 2.0; if (position_x < -maxx) position_x = -maxx; if (position_x > +maxx) position_x = +maxx; if (position_y < -maxy) position_y = -maxy; if (position_y > +maxy) position_y = +maxy; atx = position_x + sin(spin_z*M_PI/180.0) * 100.0; aty = position_y + cos(spin_z*M_PI/180.0) * 100.0; gluLookAt(position_x, position_y, 150, atx, aty, 140, 0.0, 0.0, 1.0); /* glTranslatef(position_x, position_y, -150.0); */ /* glColor3f(1.0, 1.0, 1.0); */ /* glRectf(-25.0, -25.0, 25.0, 25.0); */ glTranslatef(-maxx, -maxy, 0.0); for (i=0; i= 360.0) spin_z -= 360; break; case GLUT_KEY_RIGHT: spin_z += 1.0; if (spin_z < 0.0) spin_z += 360; break; case GLUT_KEY_UP: velocity += 1.0; if (velocity > 50.0) velocity = 10.0; break; case GLUT_KEY_DOWN: velocity -= 1.0; if (velocity < -50.0) velocity = -10.0; break; } } static void key(unsigned char k, int x, int y) { switch(k) { case ' ': velocity = 0.0; break; case 27: exit(0); break; } } static void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(30.0, (GLdouble)w/(GLdouble)h, 1.0, 10000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } static void heightfield_main() { int argc = 1; char *argv[] = { "Height Field Viewer" }; glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE); glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); glutInitWindowPosition(0, 0); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(key); glutSpecialFunc(arrows); glutIdleFunc(display); glutMainLoop(); }