/******************************************************************************* * MD2 Loader Example - by Marcello Bastea-Forte (http://marcello.cellosoft.com/) * * Contains the following modules: * MD2 Loader - loads, displays, animates MD2 (Quake 2) models for Processing * - based on C++ MD2 loader by DigiBen (http://www.gametutorials.com/Tutorials/opengl/OpenGL_Pg4.htm) * - heavily adapted and completely rewritten in Processing by Marcello (http://marcello.cellosoft.com/) * - cubic interpolation by entheh (http://bdavis.strangesoft.net/) * Spin3d - Handles nice trackball style camera movement in Processing * - based on Matrix3D code from cello3d by Marcello * PComponent - really lame Processing component engine * - by Marcello * The 3D model used here was from the MD2 Loader code this was ported from, * I have no idea who made it, but I will assume it is from Quake 2 and is * thus copyrighted by ID. ********************************************************************************/ Spin3d spin = new Spin3d(); MD2Model model; ComponentManager cm = new ComponentManager(); void setup() { size(300,300); noStroke(); noSmooth(); model = new MD2Model("tris.md2",loadImage("hobgoblin.jpg")); AnimationList list = new AnimationList(model); list.move(5,5,width-10,15); cm.add(list); } void mouseMoved() { cm.mouseMotion(); } void mouseDragged() { if (!cm.mouseMotion()) spin.mouseMoved(); } void mousePressed() { cm.mousePressed(); } void mouseReleased() { cm.mouseReleased(); } void proc() { cm.update(); spin.update(); model.update(); } void loop() { proc(); push(); drawproc(); pop(); cm.draw(); } void drawproc() { background(200); translate(width/2,height/2,0); spin.apply(); scale(4); noStroke(); noSmooth(); fill(255); model.draw(); stroke(0); noFill(); scale(30); beginShape(QUADS); vertex(-1,-1,0); vertex(1,-1,0); vertex(1,1,0); vertex(-1,1,0); endShape(); } /******************************************************************************* * PComponent - really lame Processing component engine * - by Marcello ********************************************************************************/ class ComponentManager { Vector v = new Vector(); void draw() { Enumeration e = v.elements(); while (e.hasMoreElements()) { PComponent p = (PComponent)e.nextElement(); p.draw(); } } void update() { Enumeration e = v.elements(); while (e.hasMoreElements()) { PComponent p = (PComponent)e.nextElement(); p.update(); } } boolean mousePressed() { Enumeration e = v.elements(); while (e.hasMoreElements()) { PComponent p = (PComponent)e.nextElement(); if (p.mousePressed()) return true; } return false; } boolean mouseReleased() { Enumeration e = v.elements(); while (e.hasMoreElements()) { PComponent p = (PComponent)e.nextElement(); if (p.mouseReleased()) return true; } return false; } boolean mouseMotion() { Enumeration e = v.elements(); while (e.hasMoreElements()) { PComponent p = (PComponent)e.nextElement(); if (p.mouseMotion()) return true; } return false; } void add(PComponent p) { v.addElement(p); } } class PComponent { int x, y, w, h; boolean over; boolean pressed; boolean activepress; void move(int x, int y, int w, int h) { this.x=x; this.y=y; this.w=w; this.h=h; } void draw() { translate(x,y); drawBackground(); drawContents(); drawBorder(); translate(-x,-y); } void drawBackground() { } void drawContents() { } void drawBorder() { } void update() { } boolean mouseMotion() { over = mouseX>=x && mouseY>=y && mouseX < x+w && mouseY < y+h; activepress = over && pressed; return false; } boolean mousePressed() { over = mouseX>=x && mouseY>=y && mouseX < x+w && mouseY < y+h; activepress = pressed = over; return false; } boolean mouseReleased() { over = mouseX>=x && mouseY>=y && mouseX < x+w && mouseY < y+h; activepress = pressed = false; return false; } } class AnimationList extends PComponent { MD2Model model; AnimationList(MD2Model model) { this.model = model; } void drawContents() { stroke(over ? 255 : 180); line ( 0, h/2, w, h/2); int count = model.animations.length; ellipseMode(CENTER_RADIUS); for (int i=0; i=0 && b[o]!=0) { s+=char(b[o++]); len--; } return s; } // This holds the header information that is read in at the beginning of the file class MD2Header { int magic; // This is used to identify the file int version; // The version number of the file (Must be 8) int skinWidth; // The skin width in pixels int skinHeight; // The skin height in pixels int frameSize; // The size in bytes the frames are int numSkins; // The number of skins associated with the model int numVertices; // The number of vertices (constant for each frame) int numTexCoords; // The number of texture coordinates int numTriangles; // The number of faces (polygons) int numGlCommands; // The number of gl commands int numFrames; // The number of animation frames int offsetSkins; // The offset in the file for the skin data int offsetTexCoords; // The offset in the file for the texture data int offsetTriangles; // The offset in the file for the face data int offsetFrames; // The offset in the file for the frames data int offsetGlCommands; // The offset in the file for the gl commands data int offsetEnd; // The end of the file offset MD2Header(byte[] b) { int i=0; magic = readInt4(b,i); i+=4; version = readInt4(b,i); i+=4; skinWidth = readInt4(b,i); i+=4; skinHeight = readInt4(b,i); i+=4; frameSize = readInt4(b,i); i+=4; numSkins = readInt4(b,i); i+=4; numVertices = readInt4(b,i); i+=4; numTexCoords = readInt4(b,i); i+=4; numTriangles = readInt4(b,i); i+=4; numGlCommands = readInt4(b,i); i+=4; numFrames = readInt4(b,i); i+=4; offsetSkins = readInt4(b,i); i+=4; offsetTexCoords = readInt4(b,i); i+=4; offsetTriangles = readInt4(b,i); i+=4; offsetFrames = readInt4(b,i); i+=4; offsetGlCommands = readInt4(b,i); i+=4; offsetEnd = readInt4(b,i); i+=4; } } // This is used to store the vertices that are read in for the current frame class MD2AliasTriangle { int vertex[] = new int[3]; int lightNormalIndex; MD2AliasTriangle(byte[] b, int o) { vertex[0] = 0xFF&b[o]; vertex[1] = 0xFF&b[o+1]; vertex[2] = 0xFF&b[o+2]; lightNormalIndex = 0xFF&b[o+3]; } int getSize() { return 4; } }; // This stores the normals and vertices for the frames class MD2Triangle { float vertex[] = new float[3]; float normal[] = new float[3]; int getSize() { return 4 * 6; } }; // This stores the indices into the vertex and texture coordinate arrays class MD2Face { short vertexIndices[] = new short[3]; short textureIndices[] = new short[3]; MD2Face(byte[] b, int o) { vertexIndices[0] = readShort2(b,o); o+=2; vertexIndices[1] = readShort2(b,o); o+=2; vertexIndices[2] = readShort2(b,o); o+=2; textureIndices[0] = readShort2(b,o); o+=2; textureIndices[1] = readShort2(b,o); o+=2; textureIndices[2] = readShort2(b,o); o+=2; } int getSize() { return 2 * 6; } }; // This stores UV coordinates class MD2TexCoord { short u, v; MD2TexCoord(byte[] b, int o) { u = readShort2(b,o); v = readShort2(b,o+2); } int getSize() { return 4; } }; // This stores the animation scale, translation and name information for a frame, plus verts class MD2AliasFrame { float scale[] = new float[3]; float translate[] = new float[3]; String name; MD2AliasTriangle aliasVertices[]; MD2AliasFrame(byte[] b, int o, int size) { scale[0] = readFloat4(b, o); o+=4; size -= 4; scale[1] = readFloat4(b, o); o+=4; size -= 4; scale[2] = readFloat4(b, o); o+=4; size -= 4; translate[0] = readFloat4(b, o); o+=4; size -= 4; translate[1] = readFloat4(b, o); o+=4; size -= 4; translate[2] = readFloat4(b, o); o+=4; size -= 4; name = readString(b, o, 16); o+=16; size -= 16; int aliascount = size / 4; aliasVertices = new MD2AliasTriangle[aliascount]; for (int i = 0; i='0' && c<='9') { s = s.substring(0,j); } } if (!s.equals(lastName) || i==frames.length-1) { if (lastName.length()>0) { animation.name = lastName; animation.endFrame = i; animations.addElement(animation); } animation = new MD2Animation(); animation.startFrame = i; } lastName = s; } this.animations = new MD2Animation[animations.size()]; for (int i=0; i= anim.endFrame) nextFrame = anim.startFrame; nextNextFrame = nextFrame + 1; if (nextNextFrame >= anim.endFrame) nextNextFrame = anim.startFrame; t = ReturnCurrentTime(); } float t = 0; void draw() { beginShape(TRIANGLES); texture(texture); for (int j = 0; j= 1000 / animationSpeed) { lastFrame = currentFrame; currentFrame = nextFrame; lastTime = time; } return t; } void ComputeNormals() { } }