00001
00002
00003
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,
00033 {1, 1, 1, 0.5},
00034 {1, 1, 1, 0},
00035 {1, 1, 1, 1},
00036 false
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
00064
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 ¢er = 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 ¢er = 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
00371 for (Flatland::Composite::const_iterator g = geom.begin(); g != geom.end(); ++g)
00372 ::Draw(**g, outline);
00373
00374
00375 for (Flatland::Composite::const_iterator g = geom.begin(); g != geom.end(); ++g)
00376 ::Draw(**g, filled);
00377
00378
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
00502 center = target = velocity = vec2(0, 0);
00503 zoom = 0.5f;
00504 }
00505
00506
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
00521 Resize(width, height);
00522 }
00523
00524
00525 void App::InitOde()
00526 {
00527
00528
00529
00530
00531
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
00565
00566
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
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
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
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
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
00651 void App::GetImageSize(const char *filename, int &width, int &height)
00652 {
00653
00654 assert(sizeof(int) == 4);
00655
00656
00657 std::ifstream infile(filename, std::ios_base::binary);
00658 if (!infile)
00659 fatalf("unable to open '%s'", filename);
00660
00661
00662 infile.read((char*) &width, 4);
00663 infile.read((char*) &height, 4);
00664 }
00665
00666
00667 void App::GetImageData(const char *filename, void *pixels)
00668 {
00669
00670 assert(sizeof(int) == 4);
00671
00672
00673 std::ifstream infile(filename, std::ios_base::binary);
00674 if (!infile)
00675 fatalf("unable to open '%s'", filename);
00676
00677
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
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
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
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
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 }