comparison render/render.d @ 18:7f74e064dad5

refactored code
author zzzzrrr <mason.green@gmail.com>
date Wed, 25 Mar 2009 11:28:25 -0400
parents render.d@82efafc87d54
children 4fce5596d1f6
comparison
equal deleted inserted replaced
17:82efafc87d54 18:7f74e064dad5
1 /*
2 * Copyright (c) 2009, Mason Green (zzzzrrr)
3 * Based on Box2D by Erin Catto, http://www.box2d.org
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * * Neither the name of the polygonal nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without specific
17 * prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 module openmelee.render.render;
32
33 import tango.math.Math : PI;
34
35 import xf.dog.Dog;
36 import xf.omg.core.LinearAlgebra;
37 import xf.hybrid.Event;
38 import xf.hybrid.Font;
39
40 import blaze.bzWorld : bzWorld;
41 import blaze.dynamics.bzBody : bzBody;
42 import blaze.collision.shapes.bzShape : bzShape;
43 import blaze.collision.shapes.bzShapeType;
44 import blaze.collision.shapes.bzCircle : bzCircle;
45 import blaze.collision.shapes.bzPolygon : bzPolygon;
46 import blaze.collision.shapes.bzEdge : bzEdge;
47 import blaze.collision.nbody.bzBroadPhase : bzBroadPhase, bzProxy;
48 import blaze.collision.bzCollision : bzAABB;
49 import blaze.common.bzMath : bzXForm, bzVec2, bzMul, bzClamp;
50 import blaze.common.bzConstants : k_toiSlop,k_maxProxies;
51
52 import openmelee.ships.ship : Ship;
53 import openmelee.melee.melee : Settings;
54
55 // Cursor scale factor
56 const CURSORSIZE = 0.05f;
57 const INIT_SPAWN_SIZE = 0.5f;
58 // Dragging stuffs
59 const BUNGEE_K = 1.5f;
60 // Damping factor for dragging
61 const DRAGDAMP = 20.0f;
62 // Size of hinges
63 const HINGE_RADIUS = 0.05f;
64 // Smallest allowed dimension
65 const MIN_DIMENSION = 0.1;
66 const MAX_CIRCLE_RES = 32;
67
68 /// Color for drawing. Each value has the range [0,1].
69 struct Color {
70 static Color opCall(float r, float g, float b)
71 {
72 Color u;
73 u.r = r;
74 u.g = g;
75 u.b = b;
76 return u;
77 }
78
79 float r = 0;
80 float g = 0;
81 float b = 0;
82 }
83
84 class Render
85 {
86
87 float zoom = 40;
88 vec2 viewCenter;
89 bzWorld world;
90 vec2i screenSize;
91 bool scaling = false;
92 bool full = false;
93 Settings settings;
94 Ship ship1, ship2;
95
96 this(bzWorld world, Ship s1, Ship s2, Settings settings) {
97 this.settings = settings;
98 ship1 = s1;
99 ship2 = s2;
100 this.world = world;
101 viewCenter = vec2(10, 10);
102 screenSize = vec2i.zero;
103 }
104
105 void drawCircle(GL gl, vec2 center, float radius, bool water = false, float theta = float.nan)
106 {
107 int segs = cast(int)(radius) + 20;
108 if (segs > MAX_CIRCLE_RES) segs = MAX_CIRCLE_RES;
109 double coef = 2.0 * PI / segs;
110
111 auto realTheta = (theta <>= 0 ? theta : 0);
112 if (water) {
113 gl.immediate(GL_TRIANGLE_FAN,
114 {
115 gl.Vertex2fv(center.ptr);
116 for (int n = 0; n <= segs; n++) {
117 double rads = n * coef;
118 gl.Vertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y);
119 }
120 });
121 }
122
123 gl.immediate(GL_LINE_STRIP,
124 {
125 for (int n = 0; n <= segs; n++) {
126 double rads = n * coef;
127 gl.Vertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y);
128 }
129 if (theta <>= 0)
130 gl.Vertex2fv(center.ptr);
131 });
132 }
133
134 void drawSolidCircle(GL gl, vec2 center, float radius, vec2 axis, Color color)
135 {
136 const k_segments = 25.0f;
137 const k_increment = 2.0f * PI / k_segments;
138 float theta = 0.0f;
139 gl.Enable(GL_BLEND);
140 gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
141 gl.Color4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f);
142 gl.Begin(GL_TRIANGLE_FAN);
143 for (int i = 0; i < k_segments; ++i) {
144 vec2 v = center + radius * vec2(cos(theta), sin(theta));
145 gl.Vertex2f(v.x, v.y);
146 theta += k_increment;
147 }
148 gl.End();
149 gl.Disable(GL_BLEND);
150
151 theta = 0.0f;
152 gl.Color4f(color.r, color.g, color.b, 1.0f);
153 gl.Begin(GL_LINE_LOOP);
154 for (int i = 0; i < k_segments; ++i) {
155 vec2 v = center + radius * vec2(cos(theta), sin(theta));
156 gl.Vertex2f(v.x, v.y);
157 theta += k_increment;
158 }
159 gl.End();
160
161 vec2 p = center + radius * axis;
162 gl.Begin(GL_LINES);
163 gl.Vertex2f(center.x, center.y);
164 gl.Vertex2f(p.x, p.y);
165 gl.End();
166 }
167
168 void drawPolygon(GL gl, vec2[] glVerts, Color color)
169 {
170 gl.Color3f(color.r, color.g, color.b);
171 gl.immediate(GL_LINE_LOOP,
172 {
173 foreach (v; glVerts)
174 gl.Vertex2fv(v.ptr);
175 });
176 }
177
178 void drawSolidPolygon(GL gl, vec2[] vertices, Color color)
179 {
180 gl.Enable(GL_BLEND);
181 gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
182 gl.Color4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f);
183 gl.Begin(GL_TRIANGLE_FAN);
184 for (int i = 0; i < vertices.length; ++i) {
185 gl.Vertex2f(vertices[i].x, vertices[i].y);
186 }
187 gl.End();
188 gl.Disable(GL_BLEND);
189
190 gl.Color4f(color.r, color.g, color.b, 1.0f);
191 gl.Begin(GL_LINE_LOOP);
192 for (int i = 0; i < vertices.length; ++i) {
193 gl.Vertex2f(vertices[i].x, vertices[i].y);
194 }
195 gl.End();
196 }
197
198
199 void drawPoint(GL gl, vec2 p, float size, Color color)
200 {
201 gl.Color3f(color.r, color.g, color.b);
202 gl.PointSize(size);
203 gl.Begin(GL_POINTS);
204 gl.Vertex2f(p.x, p.y);
205 gl.End();
206 gl.PointSize(1.0f);
207 }
208
209 void drawSegment(GL gl, vec2 begin, vec2 end, Color color)
210 {
211 gl.Color3f(color.r, color.g, color.b);
212 gl.immediate(GL_LINES,
213 {
214 gl.Vertex2fv(begin.ptr);
215 gl.Vertex2fv(end.ptr);
216 });
217 }
218
219 // TODO: handle inequal radii correctly
220 void connectCircles(GL gl, vec2 center1, float radius1, vec2 center2, float radius2)
221 {
222 auto d = center2 - center1;
223 if (!d.length)
224 return;
225 d *= (d.length - radius1) / d.length;
226 center1 += d;
227 center2 -= d;
228 gl.immediate(GL_LINES,
229 {
230 gl.Vertex2fv(center1.ptr);
231 gl.Vertex2fv(center2.ptr);
232 });
233 }
234
235 void drawXForm(GL gl, bzXForm xf)
236 {
237 bzVec2 p1 = xf.position, p2;
238 const k_axisScale = 0.4f;
239
240 gl.Begin(GL_LINES);
241 {
242 gl.Color3f(1.0f, 0.0f, 0.0f);
243 gl.Vertex2f(p1.x, p1.y);
244 p2 = p1 + k_axisScale * xf.R.col1;
245 gl.Vertex2f(p2.x, p2.y);
246
247 gl.Color3f(0.0f, 1.0f, 0.0f);
248 gl.Vertex2f(p1.x, p1.y);
249 p2 = p1 + k_axisScale * xf.R.col2;
250 gl.Vertex2f(p2.x, p2.y);
251 }
252 gl.End();
253 }
254
255 void drawSpring(GL gl, vec2 a, vec2 b, uint zigs)
256 {
257 zigs++;
258
259 // Portion of length dedicated to connectors
260 const float connPart = 0.2;
261
262 vec2 inc = (b - a) / (zigs);
263 // One step from a to b
264 vec2 zigLen = inc * (1 - connPart);
265 // Length of a connector
266 vec2 connLen = inc * (connPart / 2) * zigs;
267 // Width of a zig
268 vec2 zigWidth = (b - a).rotatedHalfPi.normalized;
269 gl.immediate(GL_LINE_STRIP,
270 {
271 gl.Vertex2fv(a.ptr);
272
273 a += connLen;
274 gl.Vertex2fv(a.ptr);
275
276 bool dir = true;
277 a += zigWidth / 2 + zigLen / 2;
278 for (int i = 0; i < zigs; i++) {
279 gl.Vertex2fv(a.ptr);
280 a += zigLen;
281 if (dir) {
282 a -= zigWidth;
283 }else {
284 a += zigWidth;
285 }
286 dir = !dir;
287 }
288
289 gl.Vertex2fv((b - connLen).ptr);
290 gl.Vertex2fv(b.ptr);
291 });
292 }
293
294 void drawShape(GL gl, bzShape shape, bzXForm xf, Color color, bool core)
295 {
296 Color coreColor = Color(0.9f, 0.6f, 0.6f);
297
298 switch (shape.type) {
299 case bzShapeType.CIRCLE:
300 auto circle = cast(bzCircle)shape;
301
302 vec2 center = vec2.from(bzMul(xf, circle.localPosition));
303 float radius = circle.radius;
304 vec2 axis = vec2.from(xf.R.col1);
305
306 gl.drawSolidCircle(center, radius, axis, color);
307
308 if (core) {
309 gl.Color3f(coreColor.r, coreColor.g, coreColor.b);
310 gl.drawCircle(center, radius - k_toiSlop);
311 }
312 break;
313 case bzShapeType.POLYGON:
314 {
315 bzPolygon poly = cast(bzPolygon)shape;
316 bzVec2[] vertices = poly.worldVertices;
317 vec2[] verts;
318 verts.length = vertices.length;
319 foreach (int i, v; vertices) {
320 verts[i] = vec2.from(v);
321 }
322
323 gl.drawSolidPolygon(verts, color);
324
325 if (core) {
326 bzVec2[] localCoreVertices = poly.coreVertices;
327 verts.length = localCoreVertices.length;
328 for (int i = 0; i < localCoreVertices.length; ++i) {
329 verts[i] = vec2.from(bzMul(xf, localCoreVertices[i]));
330 }
331 gl.drawPolygon(verts, coreColor);
332 }
333 }
334 break;
335
336 case bzShapeType.EDGE:
337 {
338 bzEdge edge = cast(bzEdge)shape;
339
340 vec2 p1 = vec2.from(bzMul(xf, edge.vertex1));
341 vec2 p2 = vec2.from(bzMul(xf, edge.vertex2));
342 gl.drawSegment(p1, p2, color);
343
344 if (core) {
345 p1 = vec2.from(bzMul(xf, edge.coreVertex1));
346 p2 = vec2.from(bzMul(xf, edge.coreVertex2));
347 gl.drawSegment(p1, p2, coreColor);
348 }
349 }
350 break;
351 }
352 }
353
354 void draw(vec2i screenSize, GL gl)
355 {
356
357 vec2 point1 = vec2.from(ship1.rBody.position);
358 vec2 point2 = vec2.from(ship2.rBody.position);
359 vec2 range = point1 - point2;
360 zoom = bzClamp(1000/range.length, 2, 60);
361 viewCenter = point1 - (range * 0.5f);
362
363 this.screenSize = screenSize;
364
365 gl.LoadIdentity();
366 gl.MatrixMode(GL_PROJECTION);
367 gl.LoadIdentity();
368
369 float left = -screenSize.x / zoom;
370 float right = screenSize.x / zoom;
371 float bottom = -screenSize.y / zoom;
372 float top = screenSize.y / zoom;
373
374 gl.gluOrtho2D(left, right, bottom, top);
375 gl.Translatef(-viewCenter.x, -viewCenter.y, 0);
376 gl.MatrixMode(GL_MODELVIEW);
377 gl.Disable(GL_DEPTH_TEST);
378 gl.LoadIdentity();
379 gl.Clear(GL_COLOR_BUFFER_BIT);
380
381 vec2 pp1 = vec2.from(ship2.rBody.position);
382 vec2 pp2 = vec2.from(ship2.state.target);
383
384 //gl.drawSegment(pp1, pp2, Color(0, 1, 0));
385
386 // Draw dynamic bodies
387 if (settings.drawShapes) {
388 for (bzBody b = world.bodyList; b; b = b.next) {
389 for (bzShape shape = b.shapeList; shape; shape = shape.next) {
390
391 bzShape s = shape;
392 bzXForm xf = b.xf;
393
394 if (b.isStatic) {
395 gl.drawShape(s, xf, Color(0.5f, 0.9f, 0.5f), settings.drawCoreShapes);
396 }else if (b.isSleeping) {
397 gl.drawShape(s, xf, Color(0.5f, 0.5f, 0.9f), settings.drawCoreShapes);
398 }else {
399 gl.drawShape(s, xf, Color(0.9f, 0.9f, 0.9f), settings.drawCoreShapes);
400 }
401
402 gl.LoadIdentity();
403 gl.Flush();
404 }
405 }
406 }
407
408 // Draw joints
409 /*
410 if (settings.drawJoints) {
411 Color color = Color(0, 0, 1);
412 gl.Color3f(0, 0, 1);
413
414 gl.LineWidth(1);
415 for (bzJoint joint = world.jointList; joint; joint = joint.next) {
416 auto distance = cast(bzDistanceJoint)joint;
417 auto pulley = cast(bzPulleyJoint)joint;
418 auto revolute = cast(bzRevoluteJoint)joint;
419 auto prismatic = cast(bzPrismaticJoint)joint;
420 auto line = cast(bzLineJoint)joint;
421 if (distance) {
422 color = Color(.5, .5, 0);
423 // Endpoints
424 vec2 a = vec2.from(distance.anchor1);
425 vec2 b = vec2.from(distance.anchor2);
426 // Circles
427 gl.drawCircle(a, HINGE_RADIUS);
428 gl.drawCircle(b, HINGE_RADIUS);
429 // Connecting line
430 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
431 }else if (pulley) {
432 auto a = vec2.from(pulley.anchor1);
433 auto b = vec2.from(pulley.groundAnchor1);
434 auto c = vec2.from(pulley.groundAnchor2);
435 auto d = vec2.from(pulley.anchor2);
436 gl.drawCircle(a, HINGE_RADIUS);
437 gl.drawCircle(b, HINGE_RADIUS);
438 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
439 gl.drawSegment(b, c, color);
440 gl.drawCircle(c, HINGE_RADIUS);
441 gl.drawCircle(d, HINGE_RADIUS);
442 gl.connectCircles(c, HINGE_RADIUS, d, HINGE_RADIUS);
443 }else if (revolute) {
444 auto a = vec2.from(revolute.rBody1.position);
445 auto b = vec2.from(revolute.anchor1);
446 auto c = vec2.from(revolute.rBody2.position);
447 gl.drawCircle(a, HINGE_RADIUS);
448 gl.drawCircle(b, HINGE_RADIUS);
449 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
450 gl.drawCircle(c, HINGE_RADIUS);
451 gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS);
452 }else if (prismatic) {
453 auto a = vec2.from(prismatic.rBody1.position);
454 auto b = vec2.from(prismatic.anchor1);
455 auto c = vec2.from(prismatic.rBody2.position);
456 gl.drawCircle(a, HINGE_RADIUS);
457 gl.drawCircle(b, HINGE_RADIUS);
458 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
459 gl.drawCircle(c, HINGE_RADIUS);
460 gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS);
461 }else if (line) {
462 auto a = vec2.from(line.rBody1.position);
463 auto b = vec2.from(line.anchor1);
464 auto c = vec2.from(line.rBody2.position);
465 gl.drawCircle(a, HINGE_RADIUS);
466 gl.drawCircle(b, HINGE_RADIUS);
467 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
468 gl.drawCircle(c, HINGE_RADIUS);
469 gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS);
470 }
471 }
472
473
474 if (settings.drawControllers) {
475 bzForceGenerator[] forces = world.forces;
476 foreach (f; forces) {
477 auto spring1 = cast(bzSpring1) f;
478 auto spring2 = cast(bzSpring2) f;
479 auto buoyancy = cast(bzBuoyancy) f;
480
481 if (spring1) {
482 auto bungee1 = cast(bzBungee1)spring1;
483 if (bungee1) {
484 gl.Color3f(.5, .5, 0);
485 // Endpoints
486 vec2 a = vec2.from(bungee1.rBody.position);
487 vec2 b = vec2.from(bungee1.anchor);
488 // Circles
489 gl.drawCircle(a, HINGE_RADIUS);
490 gl.drawCircle(b, HINGE_RADIUS);
491 // Connecting line
492 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
493 }else {
494 uint zigs = 10;
495 auto anchor1 = vec2.from(spring1.anchor);
496 auto anchor2 = vec2.from(spring1.rBody.position);
497 gl.drawSpring(anchor1, anchor2, zigs);
498 }
499 }
500
501 if (spring2) {
502 auto bungee2 = cast(bzBungee2)spring2;
503 if (bungee2) {
504 gl.Color3f(.5, .5, 0);
505 // Endpoints
506 vec2 a = vec2.from(bungee2.rBody.position);
507 vec2 b = vec2.from(bungee2.otherBody.position);
508 // Circles
509 gl.drawCircle(a, HINGE_RADIUS);
510 gl.drawCircle(b, HINGE_RADIUS);
511 // Connecting line
512 gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS);
513 }else {
514 uint zigs = 10;
515 auto anchor1 = vec2.from(spring2.otherBody.position);
516 auto anchor2 = vec2.from(spring2.rBody.position);
517 gl.drawSpring(anchor1, anchor2, zigs);
518 }
519 }
520
521 if(buoyancy) {
522 float plane = buoyancy.planeOffset;
523 vec2 p1 = vec2(-50, plane);
524 vec2 p2 = vec2(50, plane);
525 gl.drawSegment(p1, p2, color);
526 }
527 }
528 }
529 }
530 */
531
532 // Draw the world bounds
533 bzBroadPhase bp = world.broadPhase;
534 bzVec2 worldLower = bp.m_worldAABB.lowerBound;
535 bzVec2 worldUpper = bp.m_worldAABB.upperBound;
536 Color color = Color(0.3f, 0.9f, 0.9f);
537 vec2 vs[4];
538 vs[0] = vec2(worldLower.x, worldLower.y);
539 vs[1] = vec2(worldUpper.x, worldLower.y);
540 vs[2] = vec2(worldUpper.x, worldUpper.y);
541 vs[3] = vec2(worldLower.x, worldUpper.y);
542 drawPolygon(gl, vs, color);
543
544 // Draw axis aligned bounding boxes (bzAABB)
545 if (settings.drawAABBs) {
546 bzVec2 invQ;
547 invQ.set(1.0f / bp.m_quantizationFactor.x, 1.0f / bp.m_quantizationFactor.y);
548 color = Color(1.0f, 1.0f, 1.0f);
549
550 for (int i = 0; i < k_maxProxies; ++i) {
551 bzProxy p = bp.m_proxyPool[i];
552 if (!p.isValid) {
553 continue;
554 }
555
556 bzAABB b;
557 b.lowerBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.lowerBounds[0]].value;
558 b.lowerBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.lowerBounds[1]].value;
559 b.upperBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.upperBounds[0]].value;
560 b.upperBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.upperBounds[1]].value;
561
562 vs[0] = vec2(b.lowerBound.x, b.lowerBound.y);
563 vs[1] = vec2(b.upperBound.x, b.lowerBound.y);
564 vs[2] = vec2(b.upperBound.x, b.upperBound.y);
565 vs[3] = vec2(b.lowerBound.x, b.upperBound.y);
566
567 drawPolygon(gl, vs, color);
568 }
569 }
570 }
571 }