Mercurial > projects > openmelee
view render/render.d @ 29:da11cc30423f
Added miniD wrap
author | zzzzrrr <mason.green@gmail.com> |
---|---|
date | Mon, 30 Mar 2009 15:35:54 -0400 |
parents | 1cc6b8c0acd2 |
children |
line wrap: on
line source
/* * Copyright (c) 2009, Mason Green (zzzzrrr) * Based on Box2D by Erin Catto, http://www.box2d.org * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the polygonal nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ module openmelee.render.render; import tango.math.Math : PI, cos, sin; import blaze.bzWorld : bzWorld; import blaze.dynamics.bzBody : bzBody; import blaze.collision.shapes.bzShape : bzShape; import blaze.collision.shapes.bzShapeType; import blaze.collision.shapes.bzCircle : bzCircle; import blaze.collision.shapes.bzPolygon : bzPolygon; import blaze.collision.shapes.bzEdge : bzEdge; import blaze.collision.nbody.bzBroadPhase : bzBroadPhase, bzProxy; import blaze.collision.bzCollision : bzAABB; import blaze.common.bzMath : bzXForm, bzVec2, bzMul, bzClamp; import blaze.common.bzConstants : k_toiSlop,k_maxProxies; import openmelee.ships.ship : Ship, State; import openmelee.melee.melee : Settings; import openmelee.ai.human : Human; import derelict.opengl.gl; import derelict.opengl.glu; import openmelee.glfw.glfw; // Cursor scale factor const CURSORSIZE = 0.05f; const INIT_SPAWN_SIZE = 0.5f; // Dragging stuffs const BUNGEE_K = 1.5f; // Damping factor for dragging const DRAGDAMP = 20.0f; // Size of hinges const HINGE_RADIUS = 0.05f; // Smallest allowed dimension const MIN_DIMENSION = 0.1; const MAX_CIRCLE_RES = 32; Human human; /// Color for drawing. Each value has the range [0,1]. struct Color { static Color opCall(float r, float g, float b) { Color u; u.r = r; u.g = g; u.b = b; return u; } float r = 0; float g = 0; float b = 0; } void key(int a, int b) { human.onKey(a, b); } class Render { float zoom = 40; bzVec2 viewCenter; bzWorld world; bzVec2 screenSize; bool scaling = false; bool full = false; Settings settings; Ship ship1, ship2; bool running = true; this(bzWorld world, Ship s1, Ship s2, Human h, Settings settings) { human = h; this.settings = settings; ship1 = s1; ship2 = s2; this.world = world; viewCenter = bzVec2(10, 10); screenSize = bzVec2(800, 600); DerelictGL.load(); DerelictGLU.load(); DerelictGLFW.load(); glfwInit(); // Open window int width = cast(int) screenSize.x; int height = cast(int) screenSize.y; int ok = glfwOpenWindow(width, height, 8, 8, 8, 8, 8, 0, GLFW_WINDOW); if(!ok) { assert(0, "error loading window"); } glfwSetWindowTitle("OpenMelee"); glfwEnable(GLFW_STICKY_KEYS); GLFWkeyfun cbfun; cbfun = &key; glfwSetKeyCallback(cbfun); } ~this() { glfwTerminate(); } void update() { // Limit the fps glfwSwapInterval(1); draw(); glfwSwapBuffers(); running = cast(bool) glfwGetWindowParam(GLFW_OPENED); } void drawCircle(bzVec2 center, float radius, bool water = false, float theta = float.nan) { int segs = cast(int)(radius) + 20; if (segs > MAX_CIRCLE_RES) segs = MAX_CIRCLE_RES; double coef = 2.0 * PI / segs; auto realTheta = (theta <>= 0 ? theta : 0); if (water) { glBegin(GL_TRIANGLE_FAN); { glVertex2f(center.x, center.y); for (int n = 0; n <= segs; n++) { double rads = n * coef; glVertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y); } } glEnd(); } glBegin(GL_LINE_STRIP); { for (int n = 0; n <= segs; n++) { double rads = n * coef; glVertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y); } if (theta <>= 0) glVertex2f(center.x, center.y); } glEnd(); } void drawSolidCircle(bzVec2 center, float radius, bzVec2 axis, Color color) { const k_segments = 25.0f; const k_increment = 2.0f * PI / k_segments; float theta = 0.0f; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); glBegin(GL_TRIANGLE_FAN); for (int i = 0; i < k_segments; ++i) { bzVec2 v = center + radius * bzVec2(cos(theta), sin(theta)); glVertex2f(v.x, v.y); theta += k_increment; } glEnd(); glDisable(GL_BLEND); theta = 0.0f; glColor4f(color.r, color.g, color.b, 1.0f); glBegin(GL_LINE_LOOP); for (int i = 0; i < k_segments; ++i) { bzVec2 v = center + radius * bzVec2(cos(theta), sin(theta)); glVertex2f(v.x, v.y); theta += k_increment; } glEnd(); bzVec2 p = center + radius * axis; glBegin(GL_LINES); glVertex2f(center.x, center.y); glVertex2f(p.x, p.y); glEnd(); } void drawPolygon(bzVec2[] glVerts, Color color) { glColor3f(color.r, color.g, color.b); glBegin(GL_LINE_LOOP); { foreach (v; glVerts) { glVertex2f(v.x, v.y); } } glEnd(); } void drawSolidPolygon(bzVec2[] vertices, Color color) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); glBegin(GL_TRIANGLE_FAN); { for (int i = 0; i < vertices.length; ++i) { glVertex2f(vertices[i].x, vertices[i].y); } } glEnd(); glDisable(GL_BLEND); glColor4f(color.r, color.g, color.b, 1.0f); glBegin(GL_LINE_LOOP); { for (int i = 0; i < vertices.length; ++i) { glVertex2f(vertices[i].x, vertices[i].y); } } glEnd(); } void drawPoint(bzVec2 p, float size, Color color) { glColor3f(color.r, color.g, color.b); glPointSize(size); glBegin(GL_POINTS); glVertex2f(p.x, p.y); glEnd(); glPointSize(1.0f); } void drawSegment(bzVec2 begin, bzVec2 end, Color color) { glColor3f(color.r, color.g, color.b); glBegin(GL_LINES); { glVertex2f(begin.x, begin.y); glVertex2f(end.x, end.y); } glEnd(); } // TODO: handle inequal radii correctly void connectCircles(bzVec2 center1, float radius1, bzVec2 center2, float radius2) { auto d = center2 - center1; if (!d.length) return; d *= (d.length - radius1) / d.length; center1 += d; center2 -= d; glBegin(GL_LINES); { glVertex2f(center1.x, center1.y); glVertex2f(center2.x, center2.y); } glEnd(); } void drawXForm(bzXForm xf) { bzVec2 p1 = xf.position, p2; const k_axisScale = 0.4f; glBegin(GL_LINES); { glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(p1.x, p1.y); p2 = p1 + k_axisScale * xf.R.col1; glVertex2f(p2.x, p2.y); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(p1.x, p1.y); p2 = p1 + k_axisScale * xf.R.col2; glVertex2f(p2.x, p2.y); } glEnd(); } void drawSpring(bzVec2 a, bzVec2 b, uint zigs) { zigs++; // Portion of length dedicated to connectors const float connPart = 0.2; bzVec2 inc = (b - a) / (zigs); // One step from a to b bzVec2 zigLen = inc * (1 - connPart); // Length of a connector bzVec2 connLen = inc * (connPart / 2) * zigs; // Width of a zig bzVec2 zigWidth = (b - a).rotate(PI/2); zigWidth.normalize; glBegin(GL_LINE_STRIP); { glVertex2f(a.x, a.y); a += connLen; glVertex2f(a.x, a.y); bool dir = true; a += zigWidth / 2 + zigLen / 2; for (int i = 0; i < zigs; i++) { glVertex2f(a.x, a.y); a += zigLen; if (dir) { a -= zigWidth; }else { a += zigWidth; } dir = !dir; } glVertex2f((b - connLen).x, (b - connLen).y); glVertex2f(b.x, b.y); } glEnd(); } void drawShape(bzShape shape, bzXForm xf, Color color, bool core) { Color coreColor = Color(0.9f, 0.6f, 0.6f); switch (shape.type) { case bzShapeType.CIRCLE: auto circle = cast(bzCircle)shape; bzVec2 center = bzMul(xf, circle.localPosition); float radius = circle.radius; bzVec2 axis = xf.R.col1; drawSolidCircle(center, radius, axis, color); if (core) { glColor3f(coreColor.r, coreColor.g, coreColor.b); drawCircle(center, radius - k_toiSlop); } break; case bzShapeType.POLYGON: { bzPolygon poly = cast(bzPolygon)shape; bzVec2[] vertices = poly.worldVertices; drawSolidPolygon(vertices, color); if (core) { bzVec2[] localCoreVertices = poly.coreVertices; vertices.length = localCoreVertices.length; for (int i = 0; i < localCoreVertices.length; ++i) { vertices[i] = bzMul(xf, localCoreVertices[i]); } drawPolygon(vertices, coreColor); } } break; case bzShapeType.EDGE: { bzEdge edge = cast(bzEdge)shape; bzVec2 p1 = bzMul(xf, edge.vertex1); bzVec2 p2 = bzMul(xf, edge.vertex2); drawSegment(p1, p2, color); if (core) { p1 = bzMul(xf, edge.coreVertex1); p2 = bzMul(xf, edge.coreVertex2); drawSegment(p1, p2, coreColor); } } break; } } void draw() { if(ship2) { bzVec2 point1 = ship1.rBody.position; bzVec2 point2 = ship2.rBody.position; bzVec2 range = point1 - point2; zoom = bzClamp(1000/range.length, 2, 60); viewCenter = point1 - (range * 0.5f); } else { viewCenter = ship1.rBody.position; zoom = 10; } glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); float left = -screenSize.x / zoom; float right = screenSize.x / zoom; float bottom = -screenSize.y / zoom; float top = screenSize.y / zoom; gluOrtho2D(left, right, bottom, top); glTranslatef(-viewCenter.x, -viewCenter.y, 0); glMatrixMode(GL_MODELVIEW); glDisable(GL_DEPTH_TEST); glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT); // Draw dynamic bodies if (settings.drawShapes) { for (bzBody b = world.bodyList; b; b = b.next) { for (bzShape shape = b.shapeList; shape; shape = shape.next) { bzShape s = shape; bzXForm xf = b.xf; if (b.isStatic) { drawShape(s, xf, Color(0.5f, 0.9f, 0.5f), settings.drawCoreShapes); }else if (b.isSleeping) { drawShape(s, xf, Color(0.5f, 0.5f, 0.9f), settings.drawCoreShapes); }else { drawShape(s, xf, Color(0.9f, 0.9f, 0.9f), settings.drawCoreShapes); } glLoadIdentity(); glFlush(); } } } // Draw joints /* if (settings.drawJoints) { Color color = Color(0, 0, 1); gl.Color3f(0, 0, 1); gl.LineWidth(1); for (bzJoint joint = world.jointList; joint; joint = joint.next) { auto distance = cast(bzDistanceJoint)joint; auto pulley = cast(bzPulleyJoint)joint; auto revolute = cast(bzRevoluteJoint)joint; auto prismatic = cast(bzPrismaticJoint)joint; auto line = cast(bzLineJoint)joint; if (distance) { color = Color(.5, .5, 0); // Endpoints bzVec2 a = bzVec2.from(distance.anchor1); bzVec2 b = bzVec2.from(distance.anchor2); // Circles gl.drawCircle(a, HINGE_RADIUS); gl.drawCircle(b, HINGE_RADIUS); // Connecting line gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); }else if (pulley) { auto a = bzVec2.from(pulley.anchor1); auto b = bzVec2.from(pulley.groundAnchor1); auto c = bzVec2.from(pulley.groundAnchor2); auto d = bzVec2.from(pulley.anchor2); gl.drawCircle(a, HINGE_RADIUS); gl.drawCircle(b, HINGE_RADIUS); gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); gl.drawSegment(b, c, color); gl.drawCircle(c, HINGE_RADIUS); gl.drawCircle(d, HINGE_RADIUS); gl.connectCircles(c, HINGE_RADIUS, d, HINGE_RADIUS); }else if (revolute) { auto a = bzVec2.from(revolute.rBody1.position); auto b = bzVec2.from(revolute.anchor1); auto c = bzVec2.from(revolute.rBody2.position); gl.drawCircle(a, HINGE_RADIUS); gl.drawCircle(b, HINGE_RADIUS); gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); gl.drawCircle(c, HINGE_RADIUS); gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS); }else if (prismatic) { auto a = bzVec2.from(prismatic.rBody1.position); auto b = bzVec2.from(prismatic.anchor1); auto c = bzVec2.from(prismatic.rBody2.position); gl.drawCircle(a, HINGE_RADIUS); gl.drawCircle(b, HINGE_RADIUS); gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); gl.drawCircle(c, HINGE_RADIUS); gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS); }else if (line) { auto a = bzVec2.from(line.rBody1.position); auto b = bzVec2.from(line.anchor1); auto c = bzVec2.from(line.rBody2.position); gl.drawCircle(a, HINGE_RADIUS); gl.drawCircle(b, HINGE_RADIUS); gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); gl.drawCircle(c, HINGE_RADIUS); gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS); } } if (settings.drawControllers) { bzForceGenerator[] forces = world.forces; foreach (f; forces) { auto spring1 = cast(bzSpring1) f; auto spring2 = cast(bzSpring2) f; auto buoyancy = cast(bzBuoyancy) f; if (spring1) { auto bungee1 = cast(bzBungee1)spring1; if (bungee1) { gl.Color3f(.5, .5, 0); // Endpoints bzVec2 a = bzVec2.from(bungee1.rBody.position); bzVec2 b = bzVec2.from(bungee1.anchor); // Circles gl.drawCircle(a, HINGE_RADIUS); gl.drawCircle(b, HINGE_RADIUS); // Connecting line gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); }else { uint zigs = 10; auto anchor1 = bzVec2.from(spring1.anchor); auto anchor2 = bzVec2.from(spring1.rBody.position); gl.drawSpring(anchor1, anchor2, zigs); } } if (spring2) { auto bungee2 = cast(bzBungee2)spring2; if (bungee2) { gl.Color3f(.5, .5, 0); // Endpoints bzVec2 a = bzVec2.from(bungee2.rBody.position); bzVec2 b = bzVec2.from(bungee2.otherBody.position); // Circles gl.drawCircle(a, HINGE_RADIUS); gl.drawCircle(b, HINGE_RADIUS); // Connecting line gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); }else { uint zigs = 10; auto anchor1 = bzVec2.from(spring2.otherBody.position); auto anchor2 = bzVec2.from(spring2.rBody.position); gl.drawSpring(anchor1, anchor2, zigs); } } if(buoyancy) { float plane = buoyancy.planeOffset; bzVec2 p1 = bzVec2(-50, plane); bzVec2 p2 = bzVec2(50, plane); gl.drawSegment(p1, p2, color); } } } } */ // Draw the world bounds bzBroadPhase bp = world.broadPhase; bzVec2 worldLower = bp.m_worldAABB.lowerBound; bzVec2 worldUpper = bp.m_worldAABB.upperBound; Color color = Color(0.3f, 0.9f, 0.9f); bzVec2 vs[4]; vs[0] = bzVec2(worldLower.x, worldLower.y); vs[1] = bzVec2(worldUpper.x, worldLower.y); vs[2] = bzVec2(worldUpper.x, worldUpper.y); vs[3] = bzVec2(worldLower.x, worldUpper.y); drawPolygon(vs, color); // Draw axis aligned bounding boxes (bzAABB) if (settings.drawAABBs) { bzVec2 invQ; invQ.set(1.0f / bp.m_quantizationFactor.x, 1.0f / bp.m_quantizationFactor.y); color = Color(1.0f, 1.0f, 1.0f); for (int i = 0; i < k_maxProxies; ++i) { bzProxy p = bp.m_proxyPool[i]; if (!p.isValid) { continue; } bzAABB b; b.lowerBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.lowerBounds[0]].value; b.lowerBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.lowerBounds[1]].value; b.upperBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.upperBounds[0]].value; b.upperBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.upperBounds[1]].value; vs[0] = bzVec2(b.lowerBound.x, b.lowerBound.y); vs[1] = bzVec2(b.upperBound.x, b.lowerBound.y); vs[2] = bzVec2(b.upperBound.x, b.upperBound.y); vs[3] = bzVec2(b.lowerBound.x, b.upperBound.y); drawPolygon(vs, color); } } } }