/******************************************************************** * Example import display, shapes3d; G = graph(600, 600); node = G.node; node.rotatez(0); node.rotatex(-100); shape = cone(32, 50, 100); shape.color(0, 1, 1); node.add(shape); animate(G.render, G.node, -100, 0); * ********************************************************************/ load("zegraph.dll"); /******************************************************************** * Render to a window ********************************************************************/ function show(render) { assert(zgtype(render, "render")); size = render.size(); window(size[0], size[1], "show_callback"); function show_callback(hwnd, msg, wp, hwp, lwp, lp, hlp, llp) { if (msg == "PAINT") { render.towindow(hwnd); } else if (msg == "SIZE") { hide(); } } } /******************************************************************** * Render to a window and control rotations through an node or plot * Press arrow keys or drag mouse. Double click to start/stop * animation in every 30 ms * * Input: * render -- render object * object -- node or plot object * rotx -- initial rotation about x-axis * rotz -- initial rotation about z-axis ********************************************************************/ function animate(render, object, rotx=-60, rotz=30) { rotx0 = rotx; rotz0 = rotz; assert(zgtype(render, "render")); size = render.size(); scx = size[0] / 2; scy = size[1] / 2; r = size[0]; if (size[1] > size[0]) r = size[1]; node = null; plot = null; if (zgtype(object, "node")) { node = object; node.rotatez(rotz); node.rotatex(rotx); plot = null; } else if (zgtype(object, "plot")) { plot = object; plot.rotate(rotz, rotx); node = null; } else { error("expecting a node or plot object"); } x0 = 0; y0 = 0; cx = 0; cy = 0; drag = 0; deg = 15; clock = null; key = 39; window(size[0], size[1], "animate_callback"); function animate_callback(hwnd, msg, wp, hwp, lwp, lp, hlp, llp) { if (msg == "PAINT") { render.towindow(hwnd); } else if (msg =="KEYUP") { if (wp >= 37 && wp <= 40) { global:key = wp; if (wp == 37) // left arrow global:rotz -= deg; else if (wp == 38) // up arrow global:rotx -= deg; else if (wp == 39) // right arrow global:rotz += deg; else // down arrow global:rotx += deg; if (!isnull(node)) { node.rotatez(rotz); node.rotatex(rotx); } else { plot.rotate(rotz, rotx); } render.towindow(hwnd); } } else if (msg == "LBUTTONDOWN") { global:x0 = hlp; global:y0 = llp; global:drag = 1; } else if (msg == "LBUTTONUP") { global:drag = 0; } else if (msg == "RBUTTONUP") { global:drag = 0; if (!isnull(node)) { node.rotatez(rotz0); node.rotatex(rotx0); } else { plot.rotate(rotz0, rotx0); } render.towindow(hwnd); } else if (msg == "MOUSEMOVE") { if (drag > 0) { if (cx != x0 && cx != hlp) { if ((x0 - hlp) / (cx - hlp) < 0) { global:x0 = hlp; global:cx = x0; global:y0 = llp; global:cy = y0; return; } } if (cy != y0 && cy != llp) { if ((y0 - llp) / (cy - llp) < 0) { global:x0 = hlp; global:cx = x0; global:y0 = llp; global:cy = y0; return; } } a = arcball(x0, y0, hlp, llp, scx, scy, r); global:rotx = rotx + a[0]; global:rotz = rotz + a[1]; if (!isnull(node)) { node.rotatez(rotz); node.rotatex(rotx); } else { plot.rotate(rotz, rotx); } render.towindow(hwnd); global:cx = hlp; global:cy = llp; } } else if (msg =="LBUTTONDBLCLK") { if (clock == null) { timer(30); clock = true; } else { timer(0); clock = null; } } else if (msg == "TIMER") { if (key == 37) global:rotz -= 2; else if (key == 38) global:rotx -= 2; else if (key == 39) global:rotz += 2; else global:rotx += 2; if (!isnull(node)) { node.rotatez(rotz); node.rotatex(rotx); } else { plot.rotate(rotz, rotx); } render.towindow(hwnd); } else if (msg == "SIZE") { hide(); } } } /******************************************************************** * Arcball emulation * * Input: * x0, y0 -- mouse-down position * x1, y1 -- mouse-drag position * cx, cy -- x, y of ball center * r -- radius of the scene size * ********************************************************************/ function arcball(x0, y0, x1, y1, cx, cy, r) { r += 0.0; x0 -= cx; x0 /= r; y0 -= cy; y0 /= -r; a = x0*x0 + y0*y0; if (a > 1.0) { a = sqrt(a); x0 /= a; y0 /= a; a = 1.0; } z0 = sqrt(1 - a); x1 -= cx; x1 /= r; y1 -= cy; y1 /= -r; a = x1*x1 + y1*y1; if (a > 1.0) { a = sqrt(a); x1 /= a; y1 /= a; a = 1.0; } z1 = sqrt(1 - a); a = direction(0, 0, 0, z0, x0, y0); b = direction(0, 0, 0, z1, x1, y1); return [a[0] - b[0], b[1] - a[1]]; } /******************************************************************** * Return basic objects for general graph ********************************************************************/ function graph(w=512, h=512) { render = zegraph("render"); render.size(w, h); scene = zegraph("scene"); scene.viewport(0, 0, w, h); render.add(scene); node = zegraph("node"); root = zegraph("node"); light = zegraph("light"); scene.root(root); root.add(light, node); return ["render"=render, "scene"=scene, "root"=root, "node"=node, "light"=light]; }