/* Simple 3D graphics routines - academic use only - by Chuck Liang, Hofstra University Computer Science C++/Gtk+ version */ #include "boxworld.h" double boxworld::toRadians(int degrees) { return degrees * M_PI / 180.0; } void boxworld::setSR(double s) {SR = s;} void boxworld::setZR(double z) {ZR=z;} void boxworld::tilt(int d) {tiltR=toRadians(d);} boxworld::boxworld(int xd, int yd, int zd, double zr0, int trd) { ZR = 0.5; tiltR = M_PI/2.0; SR = 1.0; XDIM=xd; YDIM=yd; ZDIM=zd; ZR=zr0; tiltR = toRadians(trd); xshift = (int)(ZDIM * cos(tiltR) * SR); yshift = (int)(ZDIM * sin(tiltR) * SR); } boxworld::boxworld(int xd, int yd, int zd, double zr0, int trd, double sr0) { ZR = 0.5; tiltR = M_PI/2.0; XDIM=xd; YDIM=yd; ZDIM=zd; ZR=zr0; tiltR = toRadians(trd); SR = sr0; xshift = (int)(ZDIM * cos(tiltR)*SR); yshift = (int)(ZDIM * sin(tiltR)*SR); // note that here SR does not affect xshift, yshift } // critical function to convert 3d coordinate to 2d coordinate stored in // x2 and y2; returns 0 on success int boxworld::point(int x, int y, int z, int *x2, int *y2) { double s; s = (1-((1-ZR)*z/((double)ZDIM))); *x2 = (int) ((s*x) + (z * cos(tiltR) * SR)); *y2 = (int) ((s*y) + (z * sin(tiltR) * SR)); *y2 += (int)abs(yshift); if(xshift<0) *x2 -= (int)xshift; return 0; } void boxworld::drawbox(Glib::RefPtr win, int x0, int y0, int z0, int xd, int yd, int zd, Glib::RefPtr gc) { int a, b, u, v, x, y, p, q; point(x0,y0,z0,&a,&b); point(x0+xd,y0,z0,&x,&y); point(x0,y0+yd,z0,&u,&v); point(x0+xd,y0+yd,z0,&p,&q); // front win->draw_line(gc,a,b,x,y); win->draw_line(gc,a,b,u,v); win->draw_line(gc,u,v,p,q); win->draw_line(gc,p,q,x,y); // sides point(x0,y0,z0+zd,&x,&y); point(x0,y0+yd,z0+zd,&p,&q); win->draw_line(gc,a,b,x,y); win->draw_line(gc,u,v,p,q); win->draw_line(gc,x,y,p,q); point(x0+xd,y0,z0+zd,&a,&b); point(x0+xd,y0+yd,z0+zd,&u,&v); win->draw_line(gc,x,y,a,b); win->draw_line(gc,p,q,u,v); win->draw_line(gc,a,b,u,v); point(x0+xd,y0,z0,&x,&y); point(x0+xd,y0+yd,z0,&p,&q); win->draw_line(gc,a,b,x,y); win->draw_line(gc,u,v,p,q); } void boxworld::drawline(Glib::RefPtr win, int x0, int y0, int z0, int x1, int y1, int z1, Glib::RefPtr gc) { int a, b, x, y; point(x0,y0,z0,&a,&b); point(x1,y1,z1,&x,&y); win->draw_line(gc,a,b,x,y); } // fill circle with scaled radius void boxworld::drawcircle(Glib::RefPtr win, bool filled, int x0, int y0, int z0, double r, Glib::RefPtr gc) { int x, y; double rs; int cx, cy; // corners of rectangle point(x0,y0,z0,&x,&y); rs = (1-((1-ZR)*((double)z0)/ZDIM)) * r; if (rs<1) rs = 1; cx = (int)(x-rs); cy = (int)(y-rs); win->draw_arc(gc,filled,cx,cy,(int)(2*rs),(int)(2*rs),0,360*64); } double boxworld::dscale(double x, double z0) { return (1-((1-ZR)*((double)z0)/ZDIM)) * x; } // draw image to scale - w,h represent the original size of the image void boxworld::drawimage(Glib::RefPtr win, Glib::RefPtr gc, Glib::RefPtr image, int x, int y, int z, int w, int h) { int ws, hs, x2, y2; point(x,y,z,&x2,&y2); ws = (int)dscale(w,z); hs = (int)dscale(h,z); win->draw_pixbuf(gc,image,0,0,x2,y2,ws,hs,Gdk::RGB_DITHER_NONE,0,0); // image->render_to_drawable(win,gc, // 0,0,x2,y2, ws,hs,Gdk::RGB_DITHER_NONE,0,0); } // fixed original w, h: void boxworld::drawimage(Glib::RefPtr win, Glib::RefPtr gc, Glib::RefPtr image, int x, int y, int z) { int w, h, ws, hs, x2, y2; point(x,y,z,&x2,&y2); w = image->get_width(); h = image->get_height(); ws = (int)dscale(w,z); hs = (int)dscale(h,z); win->draw_pixbuf(gc,image,0,0,x2,y2,ws,hs,Gdk::RGB_DITHER_NONE,0,0); // image->render_to_drawable(win,gc, // 0,0,x2,y2, ws,hs,Gdk::RGB_DITHER_NONE,0,0); } // suggested window width and height int boxworld::wwidth() { return (int) (XDIM+abs(xshift)+20);} int boxworld::wheight() { return (int) (YDIM+abs(yshift)+40);} // g++ -c boxworld.cpp `pkg-config gtkmm-2.0 --cflags --libs`