Flatland

Documentation

SourceForge.net Logo

demo.cpp

Go to the documentation of this file.
00001 // Summary: Defines methods for the demo framework.  All OpenGL stuff goes here.
00002 // Copyright: 2007  Philip Rideout.  All rights reserved.
00003 // License: see ../source/bsd-license.txt
00004 
00005 #include <ode/source/objects.h>
00006 #include <flatland/shapes.hpp>
00007 #include <fstream>
00008 #include <string>
00009 #include "demo.hpp"
00010 #include "os.h"
00011 
00012 using Flatland::vec2;
00013 using namespace Demo;
00014 
00015 Color Color::Transparent(0,0,0,0);
00016 Color Color::Black(0,0,0,1);
00017 Color Color::White(1,1,1,1);
00018 Color Color::Red(1,0,0,1);
00019 Color Color::Green(0,1,0,1);
00020 Color Color::Blue(0,0,1,1);
00021 Color Color::PaleRed(1,0.6f,0.6f,1);
00022 Color Color::PaleYellow(0.9f,0.8f,0.5f,1);
00023 Color Color::PaleGreen(0.75f,0.85f,0.75f,1);
00024 
00025 const float Point::Size = 10;
00026 
00027 void Demo::glColor(const Color &color) { glColor4fv((float*) &color); }
00028 void Demo::glVertex(const vec2 &v) { glVertex2fv((float*) &v); }
00029 
00030 ObjectProperties Object::defaults =
00031 {
00032     2,              // outlineThickness
00033     {1, 1, 1, 0.5}, // fillColor
00034     {1, 1, 1, 0},   // altFillColor
00035     {1, 1, 1, 1},   // outlineColor
00036     false           // offset
00037 };
00038 
00039 std::stack<ObjectProperties> Object::defaultStack;
00040 
00041 #define AppInstance App::GetSingleton()
00042 #define World AppInstance.GetWorld()
00043 
00044 void Demo::Draw(const Flatland::Geometry &g, const ObjectProperties &appearance)
00045 {
00046     switch (g.GetShape())
00047     {
00048         case Flatland::Shape::Circle: DrawCircle(g, appearance); return;
00049         case Flatland::Shape::Quad: DrawQuad(g, appearance); return;
00050     }
00051 }
00052 
00053 void Demo::DrawCircle(const Flatland::Geometry &g, const ObjectProperties &appearance)
00054 {
00055     assert(g.GetShape() == Flatland::Shape::Circle);
00056     const Flatland::Circle &circle = static_cast<const Flatland::Circle&>(g);
00057 
00058     const float width = appearance.outlineThickness;
00059     const Color &fill = appearance.fillColor;
00060     const Color &outline = appearance.outlineColor;
00061     const float offset = appearance.offset ? width / 2 : 0;
00062 
00063     // We offset filled areas by width/2, which assumes that
00064     // the viewport is set up such that pixels map 1:1 to model space.
00065 
00066     float radius = circle.Radius() - offset;
00067     const int slices = (int) (radius <= 10 ? 20 : radius);
00068     const float delta = M_PI * 2 / slices;
00069 
00070     if (fill.a)
00071     {
00072         glColor(fill);
00073         glBegin(GL_POLYGON);
00074         for (float theta = 0; theta < M_PI * 2; theta += delta)
00075             glVertex(circle.Center() + vec2(sinf(theta), cosf(theta)) * radius);
00076         glEnd();
00077     }
00078 
00079     if (!width || !outline.a)
00080         return;
00081 
00082     if (width > 2)
00083     {
00084         float inner = radius - width / 2;
00085         float outer = radius + width / 2;
00086 
00087         glColor(outline);
00088         glBegin(GL_QUAD_STRIP);
00089         for (float theta = 0; theta < M_PI * 2 + delta; theta += delta)
00090         {
00091             glVertex(circle.Center() + vec2(sinf(theta), cosf(theta)) * inner);
00092             glVertex(circle.Center() + vec2(sinf(theta), cosf(theta)) * outer);
00093         }
00094         glEnd();
00095 
00096         glLineWidth(1);
00097         glBegin(GL_LINE_LOOP);
00098         for (float theta = 0; theta < M_PI * 2; theta += delta)
00099             glVertex(circle.Center() + vec2(sinf(theta), cosf(theta)) * inner);
00100         glEnd();
00101         glBegin(GL_LINE_LOOP);
00102         for (float theta = 0; theta < M_PI * 2; theta += delta)
00103             glVertex(circle.Center() + vec2(sinf(theta), cosf(theta)) * outer);
00104         glEnd();
00105 
00106         return;
00107     }
00108 
00109     glLineWidth(width);
00110     glColor(outline);
00111     glBegin(GL_LINE_LOOP);
00112     for (float theta = 0; theta < M_PI * 2; theta += delta)
00113         glVertex(circle.Center() + vec2(sinf(theta), cosf(theta)) * radius);
00114     glEnd();
00115 }
00116 
00117 void Demo::DrawQuad(const Flatland::Geometry &g, const ObjectProperties &appearance)
00118 {
00119     assert(g.GetShape() == Flatland::Shape::Quad);
00120     const Flatland::Quad &quad = static_cast<const Flatland::Quad&>(g);
00121 
00122     const float width = appearance.outlineThickness;
00123     const Color &fill = appearance.fillColor;
00124     const Color &outline = appearance.outlineColor;
00125     const float offset = appearance.offset ? width / 2 : 0;
00126 
00127     vec2 eaxis[2] =
00128     {
00129         quad.Axis(0) * (quad.Extent(0) - offset),
00130         quad.Axis(1) * (quad.Extent(1) - offset)
00131     };
00132 
00133     vec2 corners[4];
00134     const vec2 &center = quad.Center();
00135     corners[0] = center - eaxis[0] - eaxis[1];
00136     corners[1] = center + eaxis[0] - eaxis[1];
00137     corners[2] = center + eaxis[0] + eaxis[1];
00138     corners[3] = center - eaxis[0] + eaxis[1];
00139 
00140     if (fill.a)
00141     {
00142         glColor(fill);
00143         glBegin(GL_QUADS);
00144         glVertex(corners[0]);
00145         glVertex(corners[1]);
00146         glVertex(corners[2]);
00147         glVertex(corners[3]);
00148         glEnd();
00149     }
00150 
00151     if (!width || !outline.a)
00152         return;
00153 
00154     glLineWidth(width);
00155     glColor(outline);
00156     glBegin(GL_LINE_LOOP);
00157     glVertex(corners[0]);
00158     glVertex(corners[1]);
00159     glVertex(corners[2]);
00160     glVertex(corners[3]);
00161     glEnd();
00162 
00163     glPointSize(width);
00164     glBegin(GL_POINTS);
00165     glVertex(corners[0]);
00166     glVertex(corners[1]);
00167     glVertex(corners[2]);
00168     glVertex(corners[3]);
00169     glEnd();
00170     glPointSize(Point::Size);
00171 }
00172 
00173 Space::~Space()
00174 {
00175     for (m = list.begin(); m != list.end(); ++m)
00176         delete *m;
00177 }
00178 
00179 Wall::Wall(float left, float top, float right, float bottom) :
00180 object(new Flatland::Block(left, top, right, bottom))
00181 {}
00182 
00183 Wall::Wall(vec2 center, float width, float height) :
00184 object(new Flatland::Block(center, width, height))
00185 {}
00186 
00187 Block::Block(vec2 center, float width, float height) :
00188 object(new Flatland::Block(center, width, height), World.BodyCreate())
00189 {}
00190 
00191 Beam::Beam(vec2 start, vec2 end, float thickness) : Composite((start + end) / 2)
00192 {
00193     vec2 center = (start + end) / 2;
00194     float length = (end - start).length();
00195     vec2 axis(length / 2, 0);
00196 
00197     Flatland::Block *spine = new Flatland::Block(center, length, thickness);
00198     Flatland::Circle *end1 = new Flatland::Circle(center + axis, thickness / 2);
00199     Flatland::Circle *end2 = new Flatland::Circle(center - axis, thickness / 2);
00200 
00201     Add(spine);
00202     Add(end1);
00203     Add(end2);
00204 
00205     theta = 180 / M_PI * atan2f(end.y - start.y, end.x - start.x);
00206 }
00207 
00208 void Beam::Insert(Space &space)
00209 {
00210     Composite::Insert(space);
00211     GetFlatlandObject()->Rotate(theta);
00212 }
00213 
00214 void Beam::InsertFront(Space &space)
00215 {
00216     Composite::InsertFront(space);
00217     GetFlatlandObject()->Rotate(theta);
00218 }
00219 
00220 Line::Line(vec2 a, vec2 b) : object(new Flatland::Line(a, b)) {}
00221 RopeSegment::RopeSegment(vec2 a, vec2 b) : object(new Flatland::Line(a, b), World.BodyCreate()) {}
00222 
00223 Terrain::Terrain(vec2 start, float bottom, bool borders, bool borderVisibility) : bottom(bottom),
00224 borders(borders), borderVisibility(borderVisibility), object(new Flatland::Terrain(start))
00225 {}
00226 
00227 Ball::Ball(Flatland::vec2 center, float radius) :
00228 object(new Flatland::Circle(center, radius), World.BodyCreate())
00229 {
00230     object.Property().friction = 0;
00231 }
00232 
00233 Point::Point(Flatland::vec2 center) :
00234 object(new Flatland::Circle(center, Size / 2), World.BodyCreate())
00235 {
00236     Property().fillColor = Color(1,0,0,1);
00237 }
00238 
00239 Wheel::Wheel(Flatland::vec2 center, float radius) :
00240 object(new Flatland::Circle(center, radius), World.BodyCreate())
00241 {
00242     texture = 0;
00243 }
00244 
00245 Composite::Composite(vec2 centroid) :
00246 object(new Flatland::Composite(centroid), World.BodyCreate())
00247 {}
00248 
00249 void Terrain::Add(const Flatland::vec2 &v)
00250 {
00251     object.GetGeometry().push_back(v);
00252 }
00253 
00254 void Composite::Add(Flatland::Geometry *geometry)
00255 {
00256     object.GetGeometry().push_back(geometry);
00257 }
00258 
00259 void Wall::Draw() const
00260 {
00261     DrawQuad(object.GetGeometry(), Property());
00262 }
00263 
00264 void Ball::Draw() const
00265 {
00266     DrawCircle(object.GetGeometry(), Property());
00267 }
00268 
00269 void Point::Draw() const
00270 {
00271     glColor(Property().fillColor);
00272     glBegin(GL_POINTS);
00273     glVertex(object.GetGeometry().Center());
00274     glEnd();
00275 }
00276 
00277 void Block::Draw() const
00278 {
00279     DrawQuad(object.GetGeometry(), Property());
00280 }
00281 
00282 void Wheel::Draw() const
00283 {
00284     if (texture)
00285     {
00286         float radius;
00287         glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &radius);
00288         radius /= 2;
00289 
00290         vec2 axis0 = object.GetGeometry().Axis(0);
00291         vec2 axis1 = object.GetGeometry().Axis(1);
00292         vec2 eaxis[2] = { axis0 * radius, axis1 * radius };
00293 
00294         vec2 corners[4];
00295         const vec2 &center = object.GetGeometry().Center();
00296         corners[0] = center - eaxis[0] - eaxis[1];
00297         corners[1] = center + eaxis[0] - eaxis[1];
00298         corners[2] = center + eaxis[0] + eaxis[1];
00299         corners[3] = center - eaxis[0] + eaxis[1];
00300 
00301         glEnable(GL_TEXTURE_2D);
00302         glBindTexture(GL_TEXTURE_2D, texture);
00303         glColor(Color::White);
00304         glPushMatrix();
00305         glBegin(GL_QUADS);
00306         glTexCoord2f(0, 0);
00307         glVertex(corners[0]);
00308         glTexCoord2f(1, 0);
00309         glVertex(corners[1]);
00310         glTexCoord2f(1, 1);
00311         glVertex(corners[2]);
00312         glTexCoord2f(0, 1);
00313         glVertex(corners[3]);
00314         glEnd();
00315         glPopMatrix();
00316         glDisable(GL_TEXTURE_2D);
00317         return;  
00318     }
00319 
00320     const float radius = object.GetGeometry().Radius();
00321     const vec2 axis = object.GetGeometry().Axis();
00322     const vec2 center = object.GetGeometry().Center();
00323     const int slices = (int) radius;
00324     const float delta = M_PI / slices;
00325 
00326     glColor(Property().fillColor);
00327     glBegin(GL_POLYGON);
00328     for (float theta = 0; theta < M_PI * 2 + delta / 2; theta += delta)
00329     {
00330         vec2 spine(sinf(theta), cosf(theta));
00331         glVertex(center + spine.rotate(axis.flip()) * radius);
00332     }
00333     glEnd();
00334 
00335     glColor(Property().altFillColor);
00336     glBegin(GL_POLYGON);
00337     for (float theta = M_PI; theta < M_PI * 2 + delta / 2; theta += delta)
00338     {
00339         vec2 spine(sinf(theta), cosf(theta));
00340         glVertex(center + spine.rotate(axis.flip()) * radius);
00341     }
00342     glEnd();
00343 
00344     if (!Property().outlineThickness)
00345         return;
00346 
00347     glLineWidth(Property().outlineThickness);
00348     glColor(Property().outlineColor);
00349     glBegin(GL_LINE_STRIP);
00350     for (float theta = 0; theta < M_PI * 2 + delta / 2; theta += delta)
00351         glVertex(center + vec2(sinf(theta), cosf(theta)) * radius);
00352     glEnd();
00353     glBegin(GL_LINES);
00354     glVertex(center + axis * radius);
00355     glVertex(center - axis * radius);
00356     glEnd();
00357 }
00358 
00359 void Composite::Draw() const
00360 {
00361     ObjectProperties filled = Property();
00362     ObjectProperties outline = Property();
00363     filled.outlineColor = Color::Transparent;
00364     outline.fillColor = Color::Transparent;
00365     outline.offset = false;
00366     filled.offset = false;
00367 
00368     const Flatland::Composite &geom = object.GetGeometry();
00369 
00370     // Draw the outlines.
00371     for (Flatland::Composite::const_iterator g = geom.begin(); g != geom.end(); ++g)
00372         ::Draw(**g, outline);
00373 
00374     // Draw the filled portions.
00375     for (Flatland::Composite::const_iterator g = geom.begin(); g != geom.end(); ++g)
00376         ::Draw(**g, filled);
00377 
00378     // Smooth out the polygons by redrawing with aa lines.
00379     glLineWidth(1);
00380     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00381     for (Flatland::Composite::const_iterator g = geom.begin(); g != geom.end(); ++g)
00382         ::Draw(**g, filled);
00383 
00384     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00385 }
00386 
00387 void Line::Draw() const
00388 {
00389     glLineWidth(Property().outlineThickness);
00390     glColor(Property().outlineColor);
00391     glBegin(GL_LINES);
00392     glVertex(object.GetGeometry().Origin());
00393     glVertex(object.GetGeometry().End());
00394     glEnd();
00395 }
00396 
00397 void Terrain::Draw() const
00398 {
00399     const Flatland::Terrain &geom = object.GetGeometry();
00400     glBegin(GL_QUAD_STRIP);
00401     for (Flatland::Terrain::const_iterator v = geom.begin(); v != geom.end(); ++v)
00402     {
00403         float mu;
00404         if (v->y > bottom)
00405             mu = (v->y - bottom) / (geom.GetBounds().bottom - bottom);
00406         else
00407             mu = (bottom - v->y) / (bottom - geom.GetBounds().top);
00408 
00409         glColor(Color::Blend(Property().fillColor, Property().altFillColor, mu));
00410         glVertex2f(v->x, v->y + Property().outlineThickness / 2);
00411         glColor(Property().altFillColor);
00412         glVertex2f(v->x, bottom);
00413     }
00414     glEnd();
00415 
00416     if (!Property().outlineThickness)
00417         return;
00418 
00419     glLineWidth(Property().outlineThickness);
00420     glColor(Property().outlineColor);
00421     glBegin(GL_LINE_STRIP);
00422 
00423     for (Flatland::Terrain::const_iterator v = geom.begin(); v != geom.end(); ++v)
00424     {
00425         if (borders && borderVisibility && v == geom.begin())
00426             glVertex2f(v->x - 0.5f, v->y + Property().outlineThickness / 2);
00427         else if (borders && !borderVisibility && v == --geom.end())
00428             glVertex2f(v->x - 0.5f, v->y + Property().outlineThickness / 2);
00429         else
00430             glVertex2f(v->x, v->y + Property().outlineThickness / 2);
00431     }
00432     glEnd();
00433 }
00434 
00435 Line *Terrain::InsertSouthBorder(Space &space) const
00436 {
00437     vec2 begin = object.GetGeometry().front();
00438     vec2 end = object.GetGeometry().back();
00439     Line *l = new Line(vec2(begin.x - 0.5f, bottom), vec2(end.x, bottom));
00440     space << l;
00441     return l;
00442 }
00443 
00444 Line *Terrain::InsertEastBorder(Space &space) const
00445 { 
00446     vec2 begin = object.GetGeometry().front();
00447     vec2 end = object.GetGeometry().back();
00448     Line *l = new Line(end, vec2(end.x, bottom));
00449     space << l;
00450     return l;
00451 }
00452 
00453 Line *Terrain::InsertWestBorder(Space &space) const
00454 { 
00455     vec2 begin = object.GetGeometry().front();
00456     float top = begin.y;
00457     float x = begin.x - 0.5f;
00458     Line *l = new Line(vec2(x, top), vec2(x, bottom));
00459     space << l;
00460     return l;
00461 }
00462 
00463 void Demo::DrawContact(const dContact &contact)
00464 {
00465     const dContactGeom &cg = contact.geom;
00466     vec2 position(cg.pos);
00467     vec2 normal(cg.normal);
00468 
00469     glColor4f(1.0, 1.0, 1.0, 1.0);
00470     glLineWidth(5);
00471     glBegin(GL_LINES);
00472     glVertex(position);
00473     glColor4f(0, 0, 0, 0);
00474     glVertex(position + normal * 40);
00475     glEnd();
00476 }
00477 
00478 void Object::Insert(Space &space)
00479 {
00480     space.push_back(this);
00481 }
00482 
00483 void Object::InsertFront(Space &space)
00484 {
00485     space.push_front(this);
00486 }
00487 
00488 App *App::singleton = 0;
00489 
00490 App &App::GetSingleton()
00491 {
00492     assert(singleton);
00493     return *singleton;
00494 }
00495 
00496 App::App(int width, int height) : width(width), height(height)
00497 {
00498     assert(!singleton);
00499     singleton = this;
00500 
00501     // Initialize member data.
00502     center = target = velocity = vec2(0, 0);
00503     zoom = 0.5f;
00504 }
00505 
00506 /// OpenGL initialization.
00507 void App::InitGl()
00508 {
00509     glDisable(GL_DEPTH_TEST);
00510     glEnable(GL_BLEND);
00511     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00512     glEnable(GL_LINE_SMOOTH);
00513     glEnable(GL_POINT_SMOOTH);
00514     glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
00515     glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
00516     glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
00517     glLineWidth(2);
00518     glPointSize(Point::Size);
00519 
00520     // Set the viewport.
00521     Resize(width, height);
00522 }
00523 
00524 /// ODE initialization.
00525 void App::InitOde()
00526 {
00527     // ODE init stuff.
00528     // Note that autodisable is off. Something could be at the top
00529     // of a parabolic bounce where its instantaneous velocity is very close to zero,
00530     // in which case we don't want it to be deactivated.
00531     // Perhaps ODE should use acceleration or net force rather than velocity?
00532     world.SetCFM(0);
00533     world.SetAutoDisableFlag(false);
00534     world.SetAutoDisableLinearThreshold(0.25f);
00535     world.SetERP(0.2f);
00536     world.SetContactMaxCorrectingVel(1);
00537     world.SetContactSurfaceLayer(0.01f);
00538     world.SetGravity(vec2(0, 0.5f));
00539 }
00540 
00541 void App::Draw() const
00542 {
00543     Clear();
00544     DrawScene();
00545 }
00546 
00547 void App::Clear() const
00548 {
00549     glClear(GL_COLOR_BUFFER_BIT);
00550     glMatrixMode(GL_MODELVIEW);
00551     glLoadIdentity();
00552 }
00553 
00554 void App::DrawScene() const
00555 {
00556     float tx = round(-center.x) + 0.25f;
00557     float ty = round(-center.y) + 0.25f;
00558     glTranslatef(tx, ty, 0);
00559 
00560     for (Space::const_iterator i = space.begin(); i != space.end(); ++i)
00561         (*i)->Draw();
00562 }
00563 
00564 /// Sets up the viewport like this:
00565 ///   - top left corner is (0,0)
00566 ///   - bottom right corner is (+width, +height)
00567 void App::Resize(int width, int height)
00568 {
00569     float cx = width / 2.0f;
00570     float cy = height / 2.0f;
00571 
00572     glViewport(0, 0, width, height);
00573     glMatrixMode(GL_PROJECTION);
00574     glLoadIdentity();
00575     glOrtho(cx - width * zoom, cx + width * zoom, cy + height * zoom, cy - height * zoom, -2, 2);
00576     glMatrixMode(GL_MODELVIEW);
00577 
00578     this->width = width;
00579     this->height = height;
00580 }
00581 
00582 /// Obtains a color from the color wheel.
00583 Color::Color(float theta)
00584 {
00585     if (theta < 0)
00586         theta = 360 + theta;
00587     if (theta >= 360)
00588         theta -= 360;
00589 
00590     if (theta < 120)
00591     {
00592         g = theta / 120;
00593         r = 1 - g;
00594         b = 0;
00595     }
00596     else if (theta < 240)
00597     {    
00598         b = (theta - 120) / 120;
00599         g = 1 - b;
00600         r = 0;
00601     }
00602     else
00603     {
00604         r = (theta - 240) / 120;
00605         b = 1 - r;
00606         g = 0;
00607     }
00608     a = 1;
00609 }
00610 
00611 /// Increases a color's brightness.
00612 void Color::IncreaseBrightness(float factor)
00613 {
00614     r += factor;
00615     g += factor;
00616     b += factor;
00617     if (r > 1)
00618         r = 1;
00619     if (g > 1)
00620         g = 1;
00621     if (b > 1)
00622         b = 1;
00623 }
00624 
00625 /// Decreases a color's brightness.
00626 void Color::DecreaseBrightness(float factor)
00627 {
00628     r -= factor;
00629     g -= factor;
00630     b -= factor;
00631     if (r < 0)
00632         r = 0;
00633     if (g < 0)
00634         g = 0;
00635     if (b < 0)
00636         b = 0;
00637 }
00638 
00639 /// Interpolate two colors.
00640 Color Color::Blend(const Color &a, const Color &b, float mu)
00641 {
00642     Color c;
00643     c.r = a.r * mu + b.r * (1 - mu);
00644     c.g = a.g * mu + b.g * (1 - mu);
00645     c.b = a.b * mu + b.b * (1 - mu);
00646     c.a = a.a * mu + b.a * (1 - mu);
00647     return c;
00648 }
00649 
00650 /// Returns the size of a raw image file.
00651 void App::GetImageSize(const char *filename, int &width, int &height)
00652 {
00653     // for now the image loader assumes a 32-bit architecture
00654     assert(sizeof(int) == 4);
00655 
00656     // open up the rgba file
00657     std::ifstream infile(filename, std::ios_base::binary);
00658     if (!infile)
00659         fatalf("unable to open '%s'", filename);
00660 
00661     // rgba is my own file format; incredibly simple!
00662     infile.read((char*) &width, 4);
00663     infile.read((char*) &height, 4);
00664 }
00665 
00666 /// Loads pixel data from a raw image file.
00667 void App::GetImageData(const char *filename, void *pixels)
00668 {
00669     // for now the image loader assumes a 32-bit architecture
00670     assert(sizeof(int) == 4);
00671 
00672     // open up the rgba file
00673     std::ifstream infile(filename, std::ios_base::binary);
00674     if (!infile)
00675         fatalf("unable to open '%s'", filename);
00676 
00677     // rgba is my own file format; incredibly simple!
00678     int width, height;
00679     infile.read((char*) &width, 4);
00680     infile.read((char*) &height, 4);
00681     infile.read((char*) pixels, width * height * 4);
00682 }
00683 
00684 /// Creates a texture using a raw image file.  Returns the OpenGL handle for the texture.
00685 Texture App::LoadTexture(const char *filename)
00686 {
00687     int width, height;
00688     std::string path = "../tests/textures/";
00689     std::string fullpath = path + filename;
00690 
00691     std::ifstream dummy(fullpath.c_str(), std::ios_base::binary);
00692     if (!dummy)
00693         fullpath = "../" + path + filename;
00694     dummy.close();
00695 
00696     GetImageSize(fullpath.c_str(), width, height);
00697     char *pixels = new char[width * height * 4];
00698     GetImageData(fullpath.c_str(), pixels);
00699     Texture texId = LoadTexture(width, height, pixels);
00700     delete pixels;
00701     return texId;
00702 }
00703 
00704 /// Creates a texture using the given data and returns its OpenGL handle.
00705 Texture App::LoadTexture(int width, int height, const void *data)
00706 {
00707     Texture texId;
00708     glGenTextures(1, &texId);
00709     glBindTexture(GL_TEXTURE_2D, texId);
00710     glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
00711     glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
00712     glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
00713     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00714     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00715     glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
00716     return texId;
00717 }
00718 
00719 /// Advances the simulation by the given step size.
00720 void App::Step(float delta)
00721 {
00722     world.GenerateContacts(space);
00723     world.QuickStep(delta);
00724     assert(!world.IsCorrupt(space));
00725 }
00726 
00727 int App::TextureWidth(Texture id)
00728 {
00729     int width = 0;
00730     glBindTexture(GL_TEXTURE_2D, id);
00731     glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
00732     return width;
00733 }
00734 
00735 int App::TextureHeight(Texture id)
00736 {
00737     int height = 0;
00738     glBindTexture(GL_TEXTURE_2D, id);
00739     glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &height);
00740     return height;
00741 }
00742 
00743 /// Draws the given OpenGL texture using a quad.
00744 void App::Blit(Texture texId, float left, float top, Color color, bool flip)
00745 {
00746     float width;
00747     float height;
00748 
00749     glEnable(GL_TEXTURE_2D);
00750     glBindTexture(GL_TEXTURE_2D, texId);
00751     glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
00752     glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &height);
00753     glColor(color);
00754     glPushMatrix();
00755     glTranslatef(left,top,0);
00756     glBegin(GL_QUADS);
00757     glTexCoord2i(0, flip ? 1 : 0);
00758     glVertex2f(0,0);
00759     glTexCoord2i(1, flip ? 1 : 0);
00760     glVertex2f(width,0);
00761     glTexCoord2i(1, flip ? 0 : 1);
00762     glVertex2f(width,height);
00763     glTexCoord2i(0, flip ? 0 : 1);
00764     glVertex2f(0,height);
00765     glEnd();
00766     glPopMatrix();
00767     glDisable(GL_TEXTURE_2D);
00768 }
00769 
00770 void App::Zoom(float factor)
00771 {
00772     zoom += factor;
00773     Resize(width, height);
00774 }
00775 
00776 dJointID App::Glue(Object *a, Object *b)
00777 {
00778     return world.Glue(*a->GetFlatlandObject(), *b->GetFlatlandObject());
00779 }
00780 
00781 dJointID App::Anchor(Object *a, Object *b, vec2 p, float mu, float erp)
00782 {
00783     return world.Anchor(*a->GetFlatlandObject(), *b->GetFlatlandObject(), p, mu, erp);
00784 }
00785 
00786 dJointID App::Anchor(Object *a, vec2 p, float mu, float erp)
00787 {
00788     return world.Anchor(*a->GetFlatlandObject(), p, mu, erp);
00789 }
00790 
00791 dJointID App::AnchorAxis(Object *a, vec2 axis)
00792 {
00793     return world.AnchorAxis(*a->GetFlatlandObject(), axis);
00794 }
00795 
00796 Rope::Rope(vec2 start, vec2 end, float length, float tautness) : start(start), end(end), terrain(false)
00797 {
00798     const float erp = 0.01f;
00799     const float dx = 20;
00800     vec2 dir = (end - start).hat();
00801     vec2 delta = dir * dx;
00802 
00803     RopeSegment *previous = new RopeSegment(start, start + delta);
00804     segments.push_back(previous);
00805     start += delta;
00806 
00807     for (float x = dx; x < length; x += dx)
00808     {
00809         vec2 end = start + delta;
00810         RopeSegment *current = new RopeSegment(start, end);
00811         segments.push_back(current);
00812         AppInstance.Anchor(previous, current, start, tautness, erp);
00813         previous = current;
00814         start = end;
00815     }
00816     previous->GetFlatlandObject()->SetCenter(end - delta / 2);
00817 }
00818 
00819 void Rope::Insert(Space &space)
00820 {
00821     for (RopeVector::iterator i = segments.begin(); i != segments.end(); ++i)
00822         space << *i;
00823     space << this;
00824 }
00825 
00826 void Rope::Terrainify(float bottom)
00827 {
00828     this->bottom = bottom;
00829     terrain = true;
00830 }
00831 
00832 void Rope::Draw() const
00833 {
00834     if (terrain)
00835     {
00836         float minY = std::min(start.y, end.y);
00837         float maxY = std::max(start.y, end.y);
00838 
00839         Color color = Property().fillColor;
00840         glBegin(GL_QUAD_STRIP);
00841 
00842         vec2 v = start;
00843 
00844         float mu;
00845         if (v.y > bottom)
00846             mu = (v.y - bottom) / (maxY - bottom);
00847         else
00848             mu = (bottom - v.y) / (bottom - minY);
00849 
00850         glColor(Color::Blend(Property().fillColor, Property().altFillColor, mu));
00851         glVertex2f(v.x, v.y + Property().outlineThickness / 2);
00852         glColor(Property().altFillColor);
00853         glVertex2f(v.x, bottom);
00854 
00855         for (RopeVector::const_iterator i = segments.begin(); i != segments.end(); ++i)
00856         {
00857             v = (i == segments.end() - 1) ? end : (*i)->End();
00858 
00859             float mu;
00860             if (v.y > bottom)
00861                 mu = (v.y - bottom) / (maxY - bottom);
00862             else
00863                 mu = (bottom - v.y) / (bottom - minY);
00864 
00865             glColor(Color::Blend(Property().fillColor, Property().altFillColor, mu));
00866             glVertex2f(v.x, v.y + Property().outlineThickness / 2);
00867             glColor(Property().altFillColor);
00868             glVertex2f(v.x, bottom);
00869         }
00870         glEnd();
00871 
00872         if (!Property().outlineThickness)
00873             return;
00874 
00875         glLineWidth(Property().outlineThickness);
00876         glColor(Property().outlineColor);
00877         glBegin(GL_LINE_STRIP);
00878         v = start;
00879         glVertex2f(v.x, v.y + Property().outlineThickness / 2);
00880         for (RopeVector::const_iterator i = segments.begin(); i != segments.end(); ++i)
00881         {
00882             v = (i == segments.end() - 1) ? end : (*i)->End();
00883             glVertex2f(v.x, v.y + Property().outlineThickness / 2);
00884         }
00885         glEnd();
00886         return;
00887     }
00888 
00889     glLineWidth(Property().outlineThickness);
00890     glColor(Property().outlineColor);
00891     glBegin(GL_LINE_STRIP);
00892     glVertex(segments.front()->Origin());
00893     for (RopeVector::const_iterator i = segments.begin(); i != segments.end(); ++i)
00894         glVertex((*i)->End());
00895     glEnd();
00896 }
00897 
00898 Catapult::Catapult(vec2 center, float width, float height, vec2 hinge)
00899 {
00900     arm = new Block(center, width, height);
00901     arm->GetFlatlandObject()->SetMass(1);
00902     AppInstance.Anchor(arm, hinge);
00903 
00904     this->hinge = new Point(hinge);
00905     this->hinge->GetFlatlandObject()->Property().collisionMask = 0;
00906     AppInstance.Anchor(this->hinge, hinge);
00907 }
00908 
00909 void Catapult::Insert(Space &space)
00910 {
00911    space << arm;
00912    space << hinge; 
00913 }
00914 
00915 void Catapult::Rotate(float theta)
00916 {
00917     arm->GetFlatlandObject()->Rotate(theta);
00918 }
00919 
00920 Point *Catapult::InsertSouthEastAnchor(Space &space)
00921 {
00922     const float offset = Point::Size / 2;
00923     Flatland::Quad &quad = static_cast<Flatland::Quad&>(arm->GetFlatlandObject()->GetGeometry());
00924     const vec2* corners = quad.GetCorners();
00925     vec2 v = corners[2] +  vec2(offset, offset);
00926     Point *p = new Point(v);
00927     AppInstance.Anchor(p, v);
00928     space << p;
00929     return p;
00930 }
00931 
00932 Point *Catapult::InsertSouthWestAnchor(Space &space)
00933 {
00934     const float offset = Point::Size / 2;
00935     Flatland::Quad &quad = static_cast<Flatland::Quad&>(arm->GetFlatlandObject()->GetGeometry());
00936     const vec2* corners = quad.GetCorners();
00937     vec2 v = corners[3] + vec2(-offset, offset);
00938     Point *p = new Point(v);
00939     AppInstance.Anchor(p, v);
00940     space << p;
00941     return p;
00942 }
00943 
00944 Point *Catapult::InsertNorthEastAnchor(Space &space)
00945 {
00946     const float offset = Point::Size / 2;
00947     Flatland::Quad &quad = static_cast<Flatland::Quad&>(arm->GetFlatlandObject()->GetGeometry());
00948     const vec2* corners = quad.GetCorners();
00949     vec2 v = corners[1] + vec2(offset, -offset);
00950     Point *p = new Point(v);
00951     AppInstance.Anchor(p, v);
00952     space << p;
00953     return p;
00954 }
00955 
00956 Point *Catapult::InsertNorthWestAnchor(Space &space)
00957 {
00958     const float offset = Point::Size / 2;
00959     Flatland::Quad &quad = static_cast<Flatland::Quad&>(arm->GetFlatlandObject()->GetGeometry());
00960     const vec2* corners = quad.GetCorners();
00961     vec2 v = corners[0] + vec2(-offset, -offset);
00962     Point *p = new Point(v);
00963     AppInstance.Anchor(p, v);
00964     space << p;
00965     return p;
00966 }
00967 
00968 void Terrain::Insert(Space &space)
00969 {
00970     object.GetGeometry().Finalize();
00971     if (borders)
00972     {
00973         Object::PushProperties();
00974         if (!borderVisibility)
00975         {
00976             Object::Default().outlineColor = Color::Transparent;
00977             Object::Default().fillColor = Color::Transparent;
00978         }
00979         InsertSouthBorder(space);
00980         InsertEastBorder(space);
00981         InsertWestBorder(space);
00982         Object::PopProperties();
00983     }
00984     Object::Insert(space);
00985 }
00986 
00987 void Composite::Insert(Space &space)
00988 {
00989     object.GetGeometry().Finalize();
00990     Object::Insert(space);
00991 }
00992 
00993 void Composite::InsertFront(Space &space)
00994 {
00995     object.GetGeometry().Finalize();
00996     Object::InsertFront(space);
00997 }

Generated on Sat Jan 13 17:20:21 2007 for Flatland by doxygen 1.5.1