diff --git a/ChangeLog b/ChangeLog index 0269c3106f..579e604859 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Thu Jul 16 13:13:23 PDT 1998 Manish Singh + + * updated MapObject again + Thu Jul 16 04:38:19 PDT 1998 Jay Cox * brush_edit.[ch]: added a zoom indicator on the preview diff --git a/plug-ins/MapObject/CHANGES b/plug-ins/MapObject/CHANGES index 51d710e004..164a213975 100644 --- a/plug-ins/MapObject/CHANGES +++ b/plug-ins/MapObject/CHANGES @@ -1,17 +1,22 @@ -Changes (post 0.31): -==================== +Changes (post 0.3.1): +===================== --> 0.31 Merged MapPlane and MapSphere. Added support for non-interactive +-> 0.3.1 Merged MapPlane and MapSphere. Added support for non-interactive execution (for script-fu). --> 0.32 Fixed a bug in the bilinear interpolation function. Added "tile" option. +-> 0.3.2 Fixed a bug in the bilinear interpolation function. Added "tile" option. Added some icons to the material page to illustrate the effects of the parameters. I'm not sure they help much. --> 0.40 Some source/algorithm cleanups, fixed gtk+ object refcounting bugs. Some +-> 0.4.0 Some source/algorithm cleanups, fixed gtk+ object refcounting bugs. Some changes to compile with gtk+ 0.99.4. --> 1.00 First non-beta release. Replaced GckNotebook with GtkNotebook, fixed a few +-> 1.0.0 First non-beta release. Replaced GckNotebook with GtkNotebook, fixed a few annoying bugs. Better support for partial transparency (only filtered transparency now, perhaps additive later). Compiles without warnings with -Wall and -ansi. --> 1.10 Added box object and changed PDB interface accordingly; this will unfortunately +-> 1.1.0 Added box object and changed PDB interface accordingly; this will unfortunately break old scripts. The transparency code should be a little saner now. +-> 1.2.0 Added cylinder object. Fixed a few things, thanks to Yosh and + Pedro for pointing them out to me. + + + diff --git a/plug-ins/MapObject/README b/plug-ins/MapObject/README index 1c1aef505c..f57972d10c 100644 --- a/plug-ins/MapObject/README +++ b/plug-ins/MapObject/README @@ -1,11 +1,11 @@ -MapObject 1.10 -- image filter plug-in for The GIMP program +MapObject 1.2.0 -- image filter plug-in for The GIMP program =========================================================== Copyright (C) 1996-98 Tom Bech Copyright (C) 1996-98 Federico Mena Quintero -Released 17th of July, 1998 +Released 16th of July, 1998 You can reach the author(s) via E-mail: tomb@gimp.org (Tom) or quartic@gimp.org (Federico). diff --git a/plug-ins/MapObject/TODO b/plug-ins/MapObject/TODO index cab622e37c..fc9b41c76c 100644 --- a/plug-ins/MapObject/TODO +++ b/plug-ins/MapObject/TODO @@ -6,7 +6,7 @@ The MapObject plug-in "todo"-list: * Rotation by mouse (doesn't work correctly yet and is disabled). * Faster mapping code * Multiple light-sources -* More objects - cylinder? +* More objects? * Presets (including save/load) * Gray-scale/channels support * Documentation diff --git a/plug-ins/MapObject/mapobject_apply.c b/plug-ins/MapObject/mapobject_apply.c index 3b9dcfceff..2098d0f3e1 100644 --- a/plug-ins/MapObject/mapobject_apply.c +++ b/plug-ins/MapObject/mapobject_apply.c @@ -113,7 +113,44 @@ void init_compute(void) box_drawables[i]->width, box_drawables[i]->height, FALSE, FALSE); } + break; + case MAP_CYLINDER: + get_ray_color=get_ray_color_cylinder; + gck_vector3_set(&mapvals.firstaxis, 1.0,0.0,0.0); + gck_vector3_set(&mapvals.secondaxis,0.0,1.0,0.0); + gck_vector3_set(&mapvals.normal,0.0,0.0,1.0); + + ident_mat(rotmat); + + rotatemat(mapvals.alpha, &mapvals.firstaxis, a); + + matmul(a,rotmat,b); + + memcpy(rotmat, b, sizeof(gfloat)*16); + + rotatemat(mapvals.beta, &mapvals.secondaxis, a); + matmul(a,rotmat,b); + + memcpy(rotmat, b, sizeof(gfloat)*16); + + rotatemat(mapvals.gamma, &mapvals.normal, a); + matmul(a,rotmat,b); + + memcpy(rotmat, b, sizeof(gfloat)*16); + + /* Set up pixel regions for the cylinder cap images */ + /* ================================================ */ + + for (i=0;i<2;i++) + { + cylinder_drawables[i] = gimp_drawable_get (mapvals.cylindermap_id[i]); + + gimp_pixel_rgn_init (&cylinder_regions[i], cylinder_drawables[i], + 0, 0, + cylinder_drawables[i]->width, cylinder_drawables[i]->height, + FALSE, FALSE); + } break; } @@ -182,16 +219,20 @@ void compute_image(void) switch (mapvals.maptype) { - case MAP_PLANE: - gimp_progress_init("Map to object (plane)"); - break; - case MAP_SPHERE: - gimp_progress_init("Map to object (sphere)"); - break; - case MAP_BOX: - gimp_progress_init("Map to object (box)"); - break; + case MAP_PLANE: + gimp_progress_init("Map to object (plane)"); + break; + case MAP_SPHERE: + gimp_progress_init("Map to object (sphere)"); + break; + case MAP_BOX: + gimp_progress_init("Map to object (box)"); + break; + case MAP_CYLINDER: + gimp_progress_init("Map to object (cylinder)"); + break; } + if (mapvals.antialiasing==FALSE) { for (ycount=0;ycountbpp==4) + { + if (gimp_drawable_has_alpha(cylinder_drawables[image]->id)) + color.a=(gdouble)(data[3])/255.0; + else + color.a=1.0; + } + else + color.a=1.0; + + return(color); +} + void poke(gint x,gint y,GckRGB *color) { static guchar data[4]; @@ -95,7 +122,7 @@ gint checkbounds(gint x,gint y) return(TRUE); } -gint checkbounds_image(gint image, gint x,gint y) +gint checkbounds_box_image(gint image, gint x,gint y) { gint w,h; @@ -108,6 +135,19 @@ gint checkbounds_image(gint image, gint x,gint y) return(TRUE); } +gint checkbounds_cylinder_image(gint image, gint x,gint y) +{ + gint w,h; + + w = cylinder_drawables[image]->width; + h = cylinder_drawables[image]->height; + + if (x<0 || y<0 || x>=w || y>=h) + return(FALSE); + else + return(TRUE); +} + GckVector3 int_to_pos(gint x,gint y) { GckVector3 pos; @@ -190,19 +230,47 @@ GckRGB get_box_image_color(gint image,gdouble u,gdouble v) x1 = (gint)((u*(gdouble)w)); y1 = (gint)((v*(gdouble)h)); - if (checkbounds_image(image, x1,y1)==FALSE) + if (checkbounds_box_image(image, x1,y1)==FALSE) return(background); x2 = (x1 + 1); y2 = (y1 + 1); - if (checkbounds_image(image, x2,y2)==FALSE) - return(peek_image(image, x1,y1)); + if (checkbounds_box_image(image, x2,y2)==FALSE) + return(peek_box_image(image, x1,y1)); - p[0] = peek_image(image, x1, y1); - p[1] = peek_image(image, x2, y1); - p[2] = peek_image(image, x1, y2); - p[3] = peek_image(image, x2, y2); + p[0] = peek_box_image(image, x1, y1); + p[1] = peek_box_image(image, x2, y1); + p[2] = peek_box_image(image, x1, y2); + p[3] = peek_box_image(image, x2, y2); + + return(gck_bilinear_rgba(u*w, v*h, p)); +} + +GckRGB get_cylinder_image_color(gint image,gdouble u,gdouble v) +{ + gint w,h, x1, y1, x2, y2; + GckRGB p[4]; + + w = cylinder_drawables[image]->width; + h = cylinder_drawables[image]->height; + + x1 = (gint)((u*(gdouble)w)); + y1 = (gint)((v*(gdouble)h)); + + if (checkbounds_cylinder_image(image, x1,y1)==FALSE) + return(background); + + x2 = (x1 + 1); + y2 = (y1 + 1); + + if (checkbounds_cylinder_image(image, x2,y2)==FALSE) + return(peek_cylinder_image(image, x1,y1)); + + p[0] = peek_cylinder_image(image, x1, y1); + p[1] = peek_cylinder_image(image, x2, y1); + p[2] = peek_cylinder_image(image, x1, y2); + p[3] = peek_cylinder_image(image, x2, y2); return(gck_bilinear_rgba(u*w, v*h, p)); } diff --git a/plug-ins/MapObject/mapobject_image.h b/plug-ins/MapObject/mapobject_image.h index fec791462f..c151d0b3aa 100644 --- a/plug-ins/MapObject/mapobject_image.h +++ b/plug-ins/MapObject/mapobject_image.h @@ -23,6 +23,9 @@ extern GPixelRgn source_region,dest_region; extern GDrawable *box_drawables[6]; extern GPixelRgn box_regions[6]; +extern GDrawable *cylinder_drawables[2]; +extern GPixelRgn cylinder_regions[2]; + extern guchar *preview_rgb_data; extern GdkImage *image; @@ -38,15 +41,17 @@ extern GTile *current_in_tile, *current_out_tile; /* Externally visible functions */ /* ============================ */ -extern gint image_setup (GDrawable *drawable,gint interactive); -extern glong in_xy_to_index (gint x,gint y); -extern glong out_xy_to_index (gint x,gint y); -extern gint checkbounds (gint x,gint y); -extern GckRGB peek (gint x,gint y); -extern void poke (gint x,gint y,GckRGB *color); -extern GckVector3 int_to_pos (gint x,gint y); -extern void pos_to_int (gdouble x,gdouble y,gint *scr_x,gint *scr_y); -extern GckRGB get_image_color (gdouble u,gdouble v,gint *inside); -extern GckRGB get_box_image_color (gint image, gdouble u,gdouble v); +extern gint image_setup (GDrawable *drawable,gint interactive); +extern glong in_xy_to_index (gint x,gint y); +extern glong out_xy_to_index (gint x,gint y); +extern gint checkbounds (gint x,gint y); +extern GckRGB peek (gint x,gint y); +extern void poke (gint x,gint y,GckRGB *color); +extern GckVector3 int_to_pos (gint x,gint y); +extern void pos_to_int (gdouble x,gdouble y,gint *scr_x,gint *scr_y); + +extern GckRGB get_image_color (gdouble u,gdouble v,gint *inside); +extern GckRGB get_box_image_color (gint image, gdouble u,gdouble v); +extern GckRGB get_cylinder_image_color (gint image, gdouble u,gdouble v); #endif diff --git a/plug-ins/MapObject/mapobject_main.c b/plug-ins/MapObject/mapobject_main.c index c32a8dc23f..983ba0d1da 100644 --- a/plug-ins/MapObject/mapobject_main.c +++ b/plug-ins/MapObject/mapobject_main.c @@ -1,5 +1,5 @@ /*********************************************************************************/ -/* MapObject 1.10 -- image filter plug-in for The Gimp program */ +/* MapObject 1.2.0 -- image filter plug-in for The Gimp program */ /* Copyright (C) 1996-98 Tom Bech */ /* Copyright (C) 1996-98 Federico Mena Quintero */ /*===============================================================================*/ @@ -59,6 +59,8 @@ void set_default_settings(void) mapvals.alpha=mapvals.beta=mapvals.gamma=0.0; mapvals.maxdepth=3.0; mapvals.radius=0.25; + mapvals.cylinder_radius=0.25; + mapvals.cylinder_length=1.0; mapvals.preview_zoom_factor=0; @@ -82,6 +84,9 @@ void set_default_settings(void) for (i=0;i<6;i++) mapvals.boxmap_id[i] = -1; + + for (i=0;i<2;i++) + mapvals.cylindermap_id[i] = -1; } void check_drawables(GDrawable *drawable) @@ -91,7 +96,7 @@ void check_drawables(GDrawable *drawable) /* Check that boxmap images are valid */ /* ================================== */ - for (i=0;iid; @@ -100,19 +105,32 @@ void check_drawables(GDrawable *drawable) else if (gimp_drawable_gray(mapvals.boxmap_id[i])) mapvals.boxmap_id[i] = drawable->id; } + + /* Check that cylindermap images are valid */ + /* ======================================= */ + + for (i=0;i<2;i++) + { + if (mapvals.cylindermap_id[i]==-1) + mapvals.cylindermap_id[i] = drawable->id; + else if (mapvals.cylindermap_id[i]!=-1 && + gimp_drawable_image_id(mapvals.cylindermap_id[i])==-1) + mapvals.cylindermap_id[i] = drawable->id; + else if (gimp_drawable_gray(mapvals.cylindermap_id[i])) + mapvals.cylindermap_id[i] = drawable->id; + } } -MAIN() +MAIN(); static void query(void) { - static GParamDef args[] = { { PARAM_INT32, "run_mode", "Interactive (0), non-interactive (1)" }, { PARAM_IMAGE, "image", "Input image" }, { PARAM_DRAWABLE, "drawable", "Input drawable" }, - { PARAM_INT32, "maptype", "Type of mapping (0=plane,1=sphere,2=box)" }, + { PARAM_INT32, "maptype", "Type of mapping (0=plane,1=sphere,2=box,3=cylinder)" }, { PARAM_FLOAT, "viewpoint_x", "Position of viewpoint (x,y,z)" }, { PARAM_FLOAT, "viewpoint_y", "Position of viewpoint (x,y,z)" }, { PARAM_FLOAT, "viewpoint_z", "Position of viewpoint (x,y,z)" }, @@ -145,17 +163,19 @@ static void query(void) { PARAM_INT32, "tiled", "Tile source image (TRUE/FALSE)" }, { PARAM_INT32, "newimage", "Create a new image (TRUE/FALSE)" }, { PARAM_INT32, "transparentbackground", "Make background transparent (TRUE/FALSE)" }, - { PARAM_FLOAT, "radius", "Sphere radius (only used when maptype=1)" }, + { PARAM_FLOAT, "radius", "Sphere/cylinder radius (only used when maptype=1 or 3)" }, { PARAM_FLOAT, "x_scale", "Box x size (0..->)" }, { PARAM_FLOAT, "y_scale", "Box y size (0..->)" }, { PARAM_FLOAT, "z_scale", "Box z size (0..->)"}, - { PARAM_DRAWABLE, "front_drawable", "Box front face (set these to -1 if not used)" }, - { PARAM_DRAWABLE, "back_drawable", "Box back face" }, - { PARAM_DRAWABLE, "top_drawable", "Box top face" }, - { PARAM_DRAWABLE, "bottom_drawable", "Box bottom face" }, - { PARAM_DRAWABLE, "left_drawable", "Box left face" }, - { PARAM_DRAWABLE, "right_drawable", "Box right face" } - + { PARAM_FLOAT, "cylinder_length", "Cylinder length (0..->)"}, + { PARAM_DRAWABLE, "box_front_drawable", "Box front face (set these to -1 if not used)" }, + { PARAM_DRAWABLE, "box_back_drawable", "Box back face" }, + { PARAM_DRAWABLE, "box_top_drawable", "Box top face" }, + { PARAM_DRAWABLE, "box_bottom_drawable", "Box bottom face" }, + { PARAM_DRAWABLE, "box_left_drawable", "Box left face" }, + { PARAM_DRAWABLE, "box_right_drawable", "Box right face" }, + { PARAM_DRAWABLE, "cyl_top_drawable", "Cylinder top face (set these to -1 if not used)" }, + { PARAM_DRAWABLE, "cyl_bottom_drawable", "Cylinder bottom face" } }; static GParamDef *return_vals = NULL; @@ -163,11 +183,11 @@ static void query(void) static gint nreturn_vals = 0; gimp_install_procedure ("plug_in_map_object", - "Maps a picture to a object (plane, sphere or box)", + "Maps a picture to a object (plane, sphere, box or cylinder)", "No help yet", "Tom Bech & Federico Mena Quintero", "Tom Bech & Federico Mena Quintero", - "Version 1.10, July 17 1998", + "Version 1.2.0, July 16 1998", "/Filters/Distorts/Map Object", "RGB*", PROC_PLUG_IN, @@ -224,7 +244,7 @@ static void run(gchar *name, compute_image(); break; case RUN_NONINTERACTIVE: - if (nparams != 46) + if (nparams != 49) status = STATUS_CALLING_ERROR; else if (status == STATUS_SUCCESS) { @@ -264,12 +284,17 @@ static void run(gchar *name, mapvals.create_new_image = (gint)param[34].data.d_int32; mapvals.transparent_background = (gint)param[35].data.d_int32; mapvals.radius = param[36].data.d_float; + mapvals.cylinder_radius = param[36].data.d_float; mapvals.scale.x = param[37].data.d_float; mapvals.scale.y = param[38].data.d_float; mapvals.scale.z = param[39].data.d_float; - + mapvals.cylinder_length = param[40].data.d_float; + for (i=0;i<6;i++) - mapvals.boxmap_id[i] = gimp_drawable_get(param[40+i].data.d_drawable)->id; + mapvals.boxmap_id[i] = gimp_drawable_get(param[41+i].data.d_drawable)->id; + + for (i=0;i<2;i++) + mapvals.cylindermap_id[i] = gimp_drawable_get(param[47+i].data.d_drawable)->id; check_drawables(drawable); image_setup(drawable, FALSE); diff --git a/plug-ins/MapObject/mapobject_main.h b/plug-ins/MapObject/mapobject_main.h index da7a9b7b47..59fa5fe107 100644 --- a/plug-ins/MapObject/mapobject_main.h +++ b/plug-ins/MapObject/mapobject_main.h @@ -32,7 +32,8 @@ typedef enum { typedef enum { MAP_PLANE, MAP_SPHERE, - MAP_BOX + MAP_BOX, + MAP_CYLINDER } MapType; /* Typedefs */ @@ -72,6 +73,7 @@ typedef struct { gint tiled; gint showgrid; gint tooltips_enabled; + gint showcaps; glong preview_zoom_factor; @@ -79,8 +81,11 @@ typedef struct { gdouble maxdepth; gdouble pixeltreshold; gdouble radius; + gdouble cylinder_radius; + gdouble cylinder_length; gint32 boxmap_id[6]; + gint32 cylindermap_id[2]; } MapObjectValues; diff --git a/plug-ins/MapObject/mapobject_preview.c b/plug-ins/MapObject/mapobject_preview.c index 6bad536d07..884bc59af9 100644 --- a/plug-ins/MapObject/mapobject_preview.c +++ b/plug-ins/MapObject/mapobject_preview.c @@ -21,9 +21,10 @@ gint draw_line (gint n, gint startx,gint starty,gint pw,gint ph, gdouble cx1, gdouble cy1, gdouble cx2, gdouble cy2, GckVector3 a,GckVector3 b); -void draw_wireframe_plane (gint startx,gint starty,gint pw,gint ph); -void draw_wireframe_sphere (gint startx,gint starty,gint pw,gint ph); -void draw_wireframe_box (gint startx,gint starty,gint pw,gint ph); +void draw_wireframe_plane (gint startx,gint starty,gint pw,gint ph); +void draw_wireframe_sphere (gint startx,gint starty,gint pw,gint ph); +void draw_wireframe_box (gint startx,gint starty,gint pw,gint ph); +void draw_wireframe_cylinder (gint startx,gint starty,gint pw,gint ph); void clear_wireframe (void); @@ -319,6 +320,9 @@ void draw_wireframe(gint startx,gint starty,gint pw,gint ph) case MAP_BOX: draw_wireframe_box(startx,starty,pw,ph); break; + case MAP_CYLINDER: + draw_wireframe_cylinder(startx,starty,pw,ph); + break; } } @@ -619,6 +623,75 @@ void draw_wireframe_box(gint startx,gint starty,gint pw,gint ph) linetab[n].x1=-1; } +void draw_wireframe_cylinder(gint startx,gint starty,gint pw,gint ph) +{ + GckVector3 p[2*8], a, axis, scale; + gint n=0,i; + gdouble cx1,cy1,cx2,cy2; + gfloat m[16], l, angle; + + /* Compute wireframe points */ + /* ======================== */ + + init_compute(); + + scale = mapvals.scale; + gck_vector3_mul(&scale,0.5); + + l = mapvals.cylinder_length/2.0; + angle = 0; + + gck_vector3_set(&axis, 0.0,1.0,0.0); + + for (i=0;i<8;i++) + { + rotatemat(angle, &axis, m); + + gck_vector3_set(&a, mapvals.cylinder_radius,0.0,0.0); + + vecmulmat(&p[i], &a, m); + + p[i+8] = p[i]; + + p[i].y += l; + p[i+8].y -= l; + + angle += 360.0/8.0; + } + + /* Rotate and translate points */ + /* =========================== */ + + for (i=0;i<16;i++) + { + vecmulmat(&a,&p[i],rotmat); + gck_vector3_add(&p[i],&a,&mapvals.position); + } + + /* Draw the box */ + /* ============ */ + + cx1=(gdouble)startx; + cy1=(gdouble)starty; + cx2=cx1+(gdouble)pw; + cy2=cy1+(gdouble)ph; + + for (i=0;i<7;i++) + { + n = draw_line(n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+1]); + n = draw_line(n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i+8],p[i+9]); + n = draw_line(n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[i],p[i+8]); + } + + n = draw_line(n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[7],p[0]); + n = draw_line(n, startx,starty,pw,ph, cx1,cy1,cx2,cy2, p[15],p[8]); + + /* Mark end of lines */ + /* ================= */ + + linetab[n].x1=-1; +} + void clear_wireframe(void) { gint n=0; diff --git a/plug-ins/MapObject/mapobject_shade.c b/plug-ins/MapObject/mapobject_shade.c index 7f1cc08784..e6ccff3f8a 100644 --- a/plug-ins/MapObject/mapobject_shade.c +++ b/plug-ins/MapObject/mapobject_shade.c @@ -589,7 +589,7 @@ gboolean intersect_rect(gdouble u,gdouble v,gdouble w, face_info->t = (w-viewp.z)/dir.z; face_info->s.x = viewp.x + face_info->t*dir.x; face_info->s.y = viewp.y + face_info->t*dir.y; - face_info->s.z = 0.0; + face_info->s.z = w; if (face_info->s.x>=-u2 && face_info->s.x<=u2 && face_info->s.y>=-v2 && face_info->s.y<=v2) @@ -908,3 +908,314 @@ GckRGB get_ray_color_box(GckVector3 *pos) return(color); } +gboolean intersect_circle(GckVector3 vp,GckVector3 dir,gdouble w, + FaceIntersectInfo *face_info) +{ + gboolean result = FALSE; + gdouble r,d; + +#define sqr(a) a*a + + if (dir.y!=0.0) + { + face_info->t = (w-vp.y)/dir.y; + face_info->s.x = vp.x + face_info->t*dir.x; + face_info->s.y = w; + face_info->s.z = vp.z + face_info->t*dir.z; + + r = sqrt(sqr(face_info->s.x) + sqr(face_info->s.z)); + + if (r<=mapvals.cylinder_radius) + { + d = 2.0*mapvals.cylinder_radius; + face_info->u = (face_info->s.x+mapvals.cylinder_radius)/d; + face_info->v = (face_info->s.z+mapvals.cylinder_radius)/d; + result = TRUE; + } + } + +#undef sqr + + return(result); +} + +gdouble compute_angle(gdouble x,gdouble y) +{ + gdouble a = 0; + + /* Check which quadrant we're in and correct angle */ + /* =============================================== */ + + if (y==0.0) + { + if (x<0) + a = 0; + else + a = M_PI; + } + else + { + if (x!=0.0) + a = atan(y/x); + else + { + if (y>0.0) + a = M_PI/2.0; + else + a = 1.5 * M_PI; + } + + if (y<0.0 && x>0.0) /* 4th quad, a is negative */ + a = 2.0*M_PI + a; + else if (y<0.0 && x<0.0) /* 3rd quad, a is positive */ + a = M_PI + a; + else if (y>0.0 && x<0.0) /* 2nd quad, a is negative */ + a = M_PI + a; + } + + return(a); +} + +gboolean intersect_cylinder(GckVector3 vp,GckVector3 dir,FaceIntersectInfo *face_intersect) +{ + gdouble a,b,c,d,e,f,tmp,l; + gboolean result = FALSE; + gint i; + +#define sqr(a) a*a + + a = sqr(dir.x) + sqr(dir.z); + b = 2.0*(vp.x*dir.x+vp.z*dir.z); + c = sqr(vp.x)+sqr(vp.z)-sqr(mapvals.cylinder_radius); + + d = sqr(b)-4.0*a*c; + if (d>=0.0) + { + e = sqrt(d); + f = 2.0*a; + + if (f!=0.0) + { + result = TRUE; + + face_intersect[0].t = (-b+e)/f; + face_intersect[1].t = (-b-e)/f; + + if (face_intersect[0].t>face_intersect[1].t) + { + tmp = face_intersect[0].t; + face_intersect[0].t = face_intersect[1].t; + face_intersect[1].t = tmp; + } + + for (i=0;i<2;i++) + { + face_intersect[i].s.x = vp.x + face_intersect[i].t * dir.x; + face_intersect[i].s.y = vp.y + face_intersect[i].t * dir.y; + face_intersect[i].s.z = vp.z + face_intersect[i].t * dir.z; + + face_intersect[i].n = face_intersect[i].s; + face_intersect[i].n.y = 0.0; + gck_vector3_normalize(&face_intersect[i].n); + + l = mapvals.cylinder_length/2.0; + + face_intersect[i].u = compute_angle(face_intersect[i].s.x,face_intersect[i].s.z)/(2.0*M_PI); + face_intersect[i].v = (face_intersect[i].s.y+l)/mapvals.cylinder_length; + + /* Mark hitpoint as on the cylinder hull */ + /* ===================================== */ + + face_intersect[i].face = 0; + + /* Check if we're completely off the cylinder axis */ + /* =============================================== */ + + if (face_intersect[i].s.y>l || face_intersect[i].s.y<-l) + { + /* Check if we've hit a cap */ + /* ======================== */ + + if (face_intersect[i].s.y>l) + { + if (intersect_circle(vp,dir,l,&face_intersect[i])==FALSE) + result = FALSE; + else + { + face_intersect[i].face = 1; + gck_vector3_set(&face_intersect[i].n, 0.0, 1.0, 0.0); + } + } + else + { + if (intersect_circle(vp,dir,-l,&face_intersect[i])==FALSE) + result = FALSE; + else + { + face_intersect[i].face = 2; + gck_vector3_set(&face_intersect[i].n, 0.0, -1.0, 0.0); + } + } + } + } + } + } + +#undef sqr + + return(result); +} + +GckRGB get_cylinder_color(gint face, gdouble u, gdouble v) +{ + GckRGB color; + gint inside; + + if (face==0) + color = get_image_color(u,v,&inside); + else + color = get_cylinder_image_color (face-1,u,v); + + return(color); +} + +GckRGB get_ray_color_cylinder(GckVector3 *pos) +{ + GckVector3 lvp,ldir,vp,p,dir,ns,nn; + GckRGB color, color2; + gfloat m[16]; + gint i; + FaceIntersectInfo face_intersect[2]; + + color=background; + vp = mapvals.viewpoint; + p = *pos; + + vp.x = vp.x - mapvals.position.x; + vp.y = vp.y - mapvals.position.y; + vp.z = vp.z - mapvals.position.z; + + p.x = p.x - mapvals.position.x; + p.y = p.y - mapvals.position.y; + p.z = p.z - mapvals.position.z; + + /* Compute direction */ + /* ================= */ + + gck_vector3_sub(&dir,&p,&vp); + gck_vector3_normalize(&dir); + + /* Compute inverse of rotation matrix and apply it to */ + /* the viewpoint and direction. This transforms the */ + /* observer into the local coordinate system of the box */ + /* ==================================================== */ + + memcpy(m,rotmat,sizeof(gfloat)*16); + + transpose_mat(m); + + vecmulmat(&lvp,&vp,m); + vecmulmat(&ldir,&dir,m); + + if (intersect_cylinder(lvp,ldir,face_intersect)==TRUE) + { + /* We've hit the cylinder. Transform the hit points and */ + /* normals back into the world coordinate system */ + /* ==================================================== */ + + for (i=0;i<2;i++) + { + vecmulmat(&ns,&face_intersect[i].s,rotmat); + vecmulmat(&nn,&face_intersect[i].n,rotmat); + + ns.x = ns.x + mapvals.position.x; + ns.y = ns.y + mapvals.position.y; + ns.z = ns.z + mapvals.position.z; + + face_intersect[i].s = ns; + face_intersect[i].n = nn; + } + + color = get_cylinder_color(face_intersect[0].face, + face_intersect[0].u,face_intersect[0].v); + + /* Check for total transparency... */ + /* =============================== */ + + if (color.a<1.0) + { + /* Hey, we can see through here! */ + /* Lets see what's on the other side.. */ + /* =================================== */ + + color=phong_shade( + &face_intersect[0].s, + &mapvals.viewpoint, + &face_intersect[0].n, + &mapvals.lightsource.position, + &color, + &mapvals.lightsource.color, + mapvals.lightsource.type); + + gck_rgba_clamp(&color); + + color2 = get_cylinder_color(face_intersect[1].face, + face_intersect[1].u,face_intersect[1].v); + + /* Make the normal point inwards */ + /* ============================= */ + + gck_vector3_mul(&face_intersect[1].n,-1.0); + + color2=phong_shade( + &face_intersect[1].s, + &mapvals.viewpoint, + &face_intersect[1].n, + &mapvals.lightsource.position, + &color2, + &mapvals.lightsource.color, + mapvals.lightsource.type); + + gck_rgba_clamp(&color2); + + if (mapvals.transparent_background==FALSE && color2.a<1.0) + { + color2.r = (color2.r*color2.a)+(background.r*(1.0-color2.a)); + color2.g = (color2.g*color2.a)+(background.g*(1.0-color2.a)); + color2.b = (color2.b*color2.a)+(background.b*(1.0-color2.a)); + color2.a = 1.0; + } + + /* Compute a mix of the first and second colors */ + /* ============================================ */ + + color.r = color.r*color.a+(1.0-color.a)*color2.r; + color.g = color.g*color.a+(1.0-color.a)*color2.g; + color.b = color.b*color.a+(1.0-color.a)*color2.b; + color.a = color.a+color2.a; + + gck_rgba_clamp(&color); + } + else if (color.a!=0.0 && mapvals.lightsource.type!=NO_LIGHT) + { + color=phong_shade( + &face_intersect[0].s, + &mapvals.viewpoint, + &face_intersect[0].n, + &mapvals.lightsource.position, + &color, + &mapvals.lightsource.color, + mapvals.lightsource.type); + + gck_rgba_clamp(&color); + } + } + else + { + if (mapvals.transparent_background==TRUE) + color.a = 0.0; + } + + return(color); +} + diff --git a/plug-ins/MapObject/mapobject_shade.h b/plug-ins/MapObject/mapobject_shade.h index fad2b909a2..a2b3ff9e50 100644 --- a/plug-ins/MapObject/mapobject_shade.h +++ b/plug-ins/MapObject/mapobject_shade.h @@ -16,7 +16,8 @@ extern get_ray_color_func get_ray_color; extern GckRGB get_ray_color_plane (GckVector3 *pos); extern GckRGB get_ray_color_sphere (GckVector3 *pos); extern GckRGB get_ray_color_box (GckVector3 *pos); -extern void compute_bounding_box (void); +extern GckRGB get_ray_color_cylinder (GckVector3 *pos); +extern void compute_bounding_box (void); extern void vecmulmat (GckVector3 *u,GckVector3 *v,gfloat m[16]); extern void rotatemat (gfloat angle,GckVector3 *v,gfloat m[16]); diff --git a/plug-ins/MapObject/mapobject_ui.c b/plug-ins/MapObject/mapobject_ui.c index dddba3cdbf..6f5157fc16 100644 --- a/plug-ins/MapObject/mapobject_ui.c +++ b/plug-ins/MapObject/mapobject_ui.c @@ -14,8 +14,8 @@ GtkTooltips *tooltips = NULL; GdkGC *gc = NULL; GtkWidget *previewarea,*pointlightwid,*dirlightwid; -GtkWidget *xentry,*yentry,*zentry, *scale_table; -GtkWidget *images_page = NULL; +GtkWidget *xentry,*yentry,*zentry; +GtkWidget *box_page = NULL, *cylinder_page = NULL; GckRGB old_light_color; @@ -24,9 +24,10 @@ gint color_dialog_id = -1; guint left_button_pressed = FALSE, light_hit = FALSE; guint32 blackpixel,whitepixel; -GckScaleValues angle_scale_vals = { 180, 0.0, -180.0, 180.0, 0.1, 1.0, 1.0, GTK_UPDATE_CONTINUOUS,TRUE }; -GckScaleValues scale_scale_vals = { 180, 0.5, 0.01, 5.0, 0.1, 0.1, 0.1, GTK_UPDATE_CONTINUOUS,TRUE }; -GckScaleValues sample_scale_vals = { 128, 3.0, 1.0, 6.0, 1.0, 1.0, 1.0, GTK_UPDATE_CONTINUOUS,TRUE }; +GckScaleValues angle_scale_vals = { 180, 0.0, -180.0, 180.0, 0.1, 1.0, 1.0, GTK_UPDATE_CONTINUOUS,TRUE }; +GckScaleValues scale_scale_vals = { 180, 0.5, 0.01, 5.0, 0.05, 0.05, 0.05, GTK_UPDATE_CONTINUOUS,TRUE }; +GckScaleValues cyl_scale_vals = { 180, 0.5, 0.01, 2.0, 0.05, 0.05, 0.05, GTK_UPDATE_CONTINUOUS,TRUE }; +GckScaleValues sample_scale_vals = { 128, 3.0, 1.0, 6.0, 1.0, 1.0, 1.0, GTK_UPDATE_CONTINUOUS,TRUE }; gchar *light_labels[] = { @@ -41,6 +42,7 @@ gchar *map_labels[] = "Plane", "Sphere", "Box", + "Cylinder", NULL }; @@ -72,24 +74,28 @@ void toggleanti_update (GtkWidget *widget, GtkCheckButton *button); void toggletips_update (GtkWidget *widget, GtkCheckButton *button); void toggletrans_update (GtkWidget *widget, GtkCheckButton *button); -void lightmenu_callback (GtkWidget *widget, gpointer client_data); -void preview_callback (GtkWidget *widget, gpointer client_data); -void apply_callback (GtkWidget *widget, gpointer client_data); -void exit_callback (GtkWidget *widget, gpointer client_data); -void color_ok_callback (GtkWidget *widget, gpointer client_data); -void color_cancel_callback (GtkWidget *widget, gpointer client_data); -void light_color_callback (GtkWidget *widget, gpointer client_data); -gint color_delete_callback (GtkWidget *widget, GdkEvent *event, gpointer client_data); +void lightmenu_callback (GtkWidget *widget, gpointer client_data); +void preview_callback (GtkWidget *widget, gpointer client_data); +void apply_callback (GtkWidget *widget, gpointer client_data); +void exit_callback (GtkWidget *widget, gpointer client_data); +void color_ok_callback (GtkWidget *widget, gpointer client_data); +void color_cancel_callback (GtkWidget *widget, gpointer client_data); +void light_color_callback (GtkWidget *widget, gpointer client_data); void color_changed_callback (GtkColorSelection *colorsel, gpointer client_data); +gint color_delete_callback (GtkWidget *widget, GdkEvent *event, gpointer client_data); gint box_constrain (gint32 image_id, gint32 drawable_id, gpointer data); void box_drawable_callback (gint32 id, gpointer data); +gint cylinder_constrain (gint32 image_id, gint32 drawable_id, gpointer data); +void cylinder_drawable_callback (gint32 id, gpointer data); + GtkWidget *create_options_page (void); GtkWidget *create_light_page (void); GtkWidget *create_material_page (void); GtkWidget *create_orientation_page (void); -GtkWidget *create_images_page (void); +GtkWidget *create_box_page (void); +GtkWidget *create_cylinder_page (void); /******************/ /* Implementation */ @@ -164,6 +170,34 @@ void boxscale_update(GtkWidget *widget, GtkScale *scale) draw_preview_wireframe(); } +void cylinderradius_update(GtkWidget *widget, GtkScale *scale) +{ + gdouble *valueptr; + GtkAdjustment *adjustment; + + valueptr=(gdouble *)gtk_object_get_data(GTK_OBJECT(widget),"ValuePtr"); + adjustment=gtk_range_get_adjustment(GTK_RANGE(scale)); + + *valueptr=(gdouble)adjustment->value; + + if (mapvals.showgrid==TRUE) + draw_preview_wireframe(); +} + +void cylinderlength_update(GtkWidget *widget, GtkScale *scale) +{ + gdouble *valueptr; + GtkAdjustment *adjustment; + + valueptr=(gdouble *)gtk_object_get_data(GTK_OBJECT(widget),"ValuePtr"); + adjustment=gtk_range_get_adjustment(GTK_RANGE(scale)); + + *valueptr=(gdouble)adjustment->value; + + if (mapvals.showgrid==TRUE) + draw_preview_wireframe(); +} + void update_light_pos_entries(void) { gchar entrytext[64]; @@ -350,27 +384,41 @@ void mapmenu_callback(GtkWidget *widget, gpointer client_data) if (mapvals.maptype==MAP_BOX) { - gtk_widget_show(scale_table); - - if (images_page==NULL) + if (box_page==NULL) { - images_page = create_images_page(); - label=gtk_label_new("Face images"); + box_page = create_box_page(); + label=gtk_label_new("Box"); gtk_widget_show(label); - gtk_notebook_append_page(options_note_book,images_page,label); + gtk_notebook_append_page(options_note_book,box_page,label); } } else { - if (images_page!=NULL) + if (box_page!=NULL) { gtk_notebook_remove_page(options_note_book, g_list_length(options_note_book->children)-1); - images_page = NULL; + box_page = NULL; + } + + if (mapvals.maptype==MAP_CYLINDER) + { + if (cylinder_page==NULL) + { + cylinder_page = create_cylinder_page(); + label=gtk_label_new("Cylinder"); + gtk_widget_show(label); + + gtk_notebook_append_page(options_note_book,cylinder_page,label); + } + } + else if (cylinder_page!=NULL) + { + gtk_notebook_remove_page(options_note_book, + g_list_length(options_note_book->children)-1); + cylinder_page = NULL; } - - gtk_widget_hide(scale_table); } } @@ -484,8 +532,8 @@ void color_changed_callback (GtkColorSelection *colorsel, gpointer client_data) gint color_delete_callback(GtkWidget *widget, GdkEvent *event, gpointer client_data) { - color_select_diag=NULL; - return FALSE; + color_select_diag = NULL; + return(FALSE); } void color_cancel_callback(GtkWidget *widget, gpointer client_data) @@ -532,6 +580,23 @@ void box_drawable_callback(gint32 id, gpointer data) mapvals.boxmap_id[i] = id; } +gint cylinder_constrain(gint32 image_id, gint32 drawable_id, gpointer data) +{ + if (drawable_id == -1) + return(TRUE); + + return (gimp_drawable_color(drawable_id) && !gimp_drawable_indexed(drawable_id)); +} + +void cylinder_drawable_callback(gint32 id, gpointer data) +{ + gint i; + + i = (gint)gtk_object_get_data(GTK_OBJECT(data),"_mapwid_id"); + + mapvals.cylindermap_id[i] = id; +} + /******************************/ /* Preview area event handler */ /******************************/ @@ -1014,6 +1079,52 @@ GtkWidget *create_orientation_page(void) gtk_tooltips_set_tip(tooltips,widget2,"Rotation angle about Y axis",NULL); gtk_tooltips_set_tip(tooltips,widget3,"Rotation angle about Z axis",NULL); + gtk_widget_show(table); + gtk_widget_show(vbox); + gtk_widget_show(frame); + + gtk_widget_show(page); + + return page; +} + +GtkWidget *create_box_page(void) +{ + GtkWidget *page,*frame,*vbox,*label,*table; + GtkWidget *widget1,*widget2,*widget3,*scale_table; + gint i; + gchar *labels[6] = {"Front:","Back:","Top:","Bottom:","Left:","Right:"}; + + page=gck_vbox_new(NULL,FALSE,FALSE,FALSE,0,0,0); + + frame=gck_frame_new("Map images to box faces",page,GTK_SHADOW_ETCHED_IN,TRUE,TRUE,0,5); + vbox=gck_vbox_new(frame,FALSE,FALSE,FALSE,0,0,5); + + table = gtk_table_new(6,2,FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + gtk_box_pack_start(GTK_BOX(vbox),table,FALSE,FALSE,5); + + /* Option menues */ + /* ============= */ + + for (i=0;i<6;i++) + { + label=gck_label_aligned_new(labels[i],NULL,GCK_ALIGN_RIGHT,0.7); + gtk_table_attach(GTK_TABLE(table),label,0,1,i,i+1, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL, 0,0); + gtk_widget_show(label); + + widget1=gtk_option_menu_new(); + gtk_table_attach(GTK_TABLE(table),widget1, 1,2, i,i+1, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL, 0,0); + gtk_widget_show(widget1); + + gtk_object_set_data(GTK_OBJECT(widget1),"_mapwid_id",(gpointer)i); + + widget2 = gimp_drawable_menu_new (box_constrain, box_drawable_callback, + (gpointer)widget1, mapvals.boxmap_id[i]); + gtk_option_menu_set_menu(GTK_OPTION_MENU(widget1), widget2); + } + /* Scale scales */ /* ============ */ @@ -1055,9 +1166,7 @@ GtkWidget *create_orientation_page(void) gtk_tooltips_set_tip(tooltips,widget2,"Y scale (size)",NULL); gtk_tooltips_set_tip(tooltips,widget3,"Z scale (size)",NULL); - if (mapvals.maptype==MAP_BOX) - gtk_widget_show(scale_table); - + gtk_widget_show(scale_table); gtk_widget_show(table); gtk_widget_show(vbox); gtk_widget_show(frame); @@ -1067,19 +1176,19 @@ GtkWidget *create_orientation_page(void) return page; } -GtkWidget *create_images_page(void) +GtkWidget *create_cylinder_page(void) { GtkWidget *page,*frame,*vbox,*label,*table; - GtkWidget *widget1,*widget2; + GtkWidget *widget1,*widget2,*scale_table; gint i; - gchar *labels[6] = {"Front:","Back:","Top:","Bottom:","Left:","Right:"}; + gchar *labels[6] = {"Top:","Bottom:"}; page=gck_vbox_new(NULL,FALSE,FALSE,FALSE,0,0,0); - frame=gck_frame_new("Map images to box faces",page,GTK_SHADOW_ETCHED_IN,TRUE,TRUE,0,5); + frame=gck_frame_new("Images for the cap faces",page,GTK_SHADOW_ETCHED_IN,FALSE,FALSE,0,5); vbox=gck_vbox_new(frame,FALSE,FALSE,FALSE,0,0,5); - table = gtk_table_new(6,2,FALSE); + table = gtk_table_new(2,2,FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), 5); gtk_table_set_col_spacings(GTK_TABLE(table), 5); gtk_box_pack_start(GTK_BOX(vbox),table,FALSE,FALSE,5); @@ -1087,7 +1196,7 @@ GtkWidget *create_images_page(void) /* Option menues */ /* ============= */ - for (i=0;i<6;i++) + for (i=0;i<2;i++) { label=gck_label_aligned_new(labels[i],NULL,GCK_ALIGN_RIGHT,0.7); gtk_table_attach(GTK_TABLE(table),label,0,1,i,i+1, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL, 0,0); @@ -1099,12 +1208,47 @@ GtkWidget *create_images_page(void) gtk_object_set_data(GTK_OBJECT(widget1),"_mapwid_id",(gpointer)i); - widget2 = gimp_drawable_menu_new (box_constrain, box_drawable_callback, - (gpointer)widget1, mapvals.boxmap_id[i]); + widget2 = gimp_drawable_menu_new (cylinder_constrain, cylinder_drawable_callback, + (gpointer)widget1, mapvals.cylindermap_id[i]); gtk_option_menu_set_menu(GTK_OPTION_MENU(widget1), widget2); } + gtk_widget_show(vbox); + gtk_widget_show(frame); gtk_widget_show(table); + + frame=gck_frame_new("Size",page,GTK_SHADOW_ETCHED_IN,FALSE,FALSE,0,5); + vbox=gck_vbox_new(frame,FALSE,FALSE,FALSE,0,0,5); + + scale_table = gtk_table_new(2,2,FALSE); + gtk_box_pack_start(GTK_BOX(vbox),scale_table,FALSE,FALSE,5); + + label=gck_label_aligned_new("Radius:",NULL,GCK_ALIGN_RIGHT,0.7); + gtk_table_attach(GTK_TABLE(scale_table),label,0,1,0,1, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL, 0,0); + gtk_widget_show(label); + + label=gck_label_aligned_new("Length:",NULL,GCK_ALIGN_RIGHT,0.7); + gtk_table_attach(GTK_TABLE(scale_table),label,0,1,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL, 0,0); + gtk_widget_show(label); + + cyl_scale_vals.value = mapvals.cylinder_radius; + widget1=gck_hscale_new(NULL,NULL,&cyl_scale_vals,(GtkSignalFunc)cylinderradius_update); + cyl_scale_vals.value = mapvals.cylinder_length; + widget2=gck_hscale_new(NULL,NULL,&cyl_scale_vals,(GtkSignalFunc)cylinderlength_update); + + gtk_table_attach(GTK_TABLE(scale_table),widget1,1,2,0,1, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL, 0,0); + gtk_table_attach(GTK_TABLE(scale_table),widget2,1,2,1,2, GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL, 0,0); + + gtk_widget_show(widget1); + gtk_widget_show(widget2); + + gtk_object_set_data(GTK_OBJECT(widget1),"ValuePtr",(gpointer)&mapvals.cylinder_radius); + gtk_object_set_data(GTK_OBJECT(widget2),"ValuePtr",(gpointer)&mapvals.cylinder_length); + + gtk_tooltips_set_tip(tooltips,widget1,"Cylinder radius",NULL); + gtk_tooltips_set_tip(tooltips,widget2,"Cylinder length",NULL); + + gtk_widget_show(scale_table); gtk_widget_show(vbox); gtk_widget_show(frame); @@ -1152,11 +1296,19 @@ void create_main_notebook(GtkWidget *container) if (mapvals.maptype==MAP_BOX) { - images_page = create_images_page(); - label=gtk_label_new("Face images"); + box_page = create_box_page(); + label=gtk_label_new("Box"); gtk_widget_show(label); - gtk_notebook_append_page(options_note_book,images_page,label); + gtk_notebook_append_page(options_note_book,box_page,label); + } + else if (mapvals.maptype==MAP_CYLINDER) + { + cylinder_page = create_cylinder_page(); + label=gtk_label_new("Cylinder"); + gtk_widget_show(label); + + gtk_notebook_append_page(options_note_book,cylinder_page,label); } gtk_widget_show(GTK_WIDGET(options_note_book));