00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "gamepad-vgfx.h"
00037
00038 #include "color/color.h"
00039 #include "perf/perf.h"
00040 #include "vgfx/request.h"
00041 #include "vgfx/vgfx.h"
00042
00043
00044 namespace gamepad {
00045
00046
00047
00048 TypeVgfxRenderer::~TypeVgfxRenderer(void) throw() { }
00049
00050
00051
00052
00053
00054
00055
00056
00057 static void
00058 addFloat
00059 (
00060 IN dictionary_t& data,
00061 IN const char * key,
00062 IN float val
00063 )
00064 {
00065 ASSERT(key, "null");
00066
00067 const int bufsize = 32;
00068 char buffer[bufsize];
00069
00070 snprintf(buffer, bufsize, "%f", val);
00071
00072 data[key] = buffer;
00073 }
00074
00075
00076
00077 static bool
00078 getField
00079 (
00080 IN vgfx::ObjectMap * map,
00081 IN const char * id,
00082 IN const char * field,
00083 OUT std::string& value
00084 )
00085 {
00086 ASSERT(map, "null");
00087 ASSERT(id, "null");
00088 ASSERT(field, "null");
00089 value = "";
00090
00091 vgfx::Primitive * obj = map->findObject(id);
00092 if (!obj)
00093 return false;
00094
00095 VecString path;
00096 path.push_back("meta");
00097 path.push_back(field);
00098
00099 dictionary_t data;
00100
00101 if (!obj->doesContainerExist(path)) {
00102 return false;
00103 }
00104
00105 obj->getContainerDictionary(path, data);
00106 const char * val = getValue(data, field);
00107 if (!val)
00108 return false;
00109 value = val;
00110 return true;
00111 }
00112
00113
00114
00115 static void
00116 addOrMoveObject
00117 (
00118 IN vgfx::ObjectMap * map,
00119 IN vgfx::Drawer * drawer,
00120 IN const char * baseId,
00121 IN const char * newId,
00122 IN float x,
00123 IN float y,
00124 IN float phi
00125 )
00126 {
00127 ASSERT(map, "null");
00128 ASSERT(drawer, "null");
00129 ASSERT(baseId, "null");
00130 ASSERT(newId, "null");
00131
00132
00133 vgfx::Primitive * root = map->findObject("root");
00134 ASSERT_THROW(root, "gamepad vector graphics contains no 'root'?");
00135
00136 VecString path;
00137 path.push_back("object");
00138 path.push_back(newId);
00139
00140 if (!root->doesContainerExist(path)) {
00141
00142 vgfx::Request req;
00143 req.addObject("root", newId, baseId, x, y, 0, phi);
00144 std::string request = req.get();
00145
00146 std::istringstream iss(request.c_str());
00147 std::string undo, diagnostic;
00148 ASSERT_THROW(vgfx::processRequest(map, iss, false, undo, diagnostic),
00149 "Failed to add new object: " << diagnostic);
00150
00151
00152 xform_2d_t T;
00153 T.setIdentity();
00154 root->recalcBoundingRect("*", drawer, T);
00155 return;
00156 }
00157
00158
00159 dictionary_t data;
00160 addFloat(data, "x", x);
00161 addFloat(data, "y", y);
00162 addFloat(data, "phi", phi);
00163
00164 root->setContainerDictionary(path, data);
00165 }
00166
00167
00168
00169 static void
00170 removeObject
00171 (
00172 IN vgfx::ObjectMap * map,
00173 IN const char * id
00174 )
00175 {
00176 ASSERT(map, "null");
00177 ASSERT(id, "null");
00178
00179
00180 vgfx::Primitive * root = map->findObject("root");
00181 ASSERT_THROW(root, "gamepad vector graphics contains no 'root'?");
00182
00183 VecString path;
00184 path.push_back("object");
00185 path.push_back(id);
00186
00187 if (root->doesContainerExist(path)) {
00188 root->removeContainer(path);
00189 }
00190 }
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 class Renderer : public TypeVgfxRenderer {
00202 public:
00203
00204 Renderer(void) throw();
00205 ~Renderer(void) throw() { }
00206
00207
00208 void initialize(IN Type * type,
00209 IN smart_ptr<vgfx::Drawer>& drawer);
00210
00211
00212 void setIntensity(IN const char * logical, IN float intensity);
00213 void setPosition(IN const char * logical,
00214 IN float x, IN float y);
00215 void draw(IN int xOffest, IN int yOffset,
00216 IN int width, IN int height);
00217
00218 private:
00219
00220 struct logical_rec_t {
00221
00222 logical_rec_t(void) throw() { this->clear(); }
00223 void clear(void) throw() {
00224 baseColor.clear();
00225 }
00226
00227
00228 glut_color_t baseColor;
00229 };
00230
00231 typedef std::map<std::string, logical_rec_t> logical_map_t;
00232
00233
00234 float getScaling(IN int width, IN int height);
00235 logical_rec_t * getLogical(IN const char * logical);
00236 void setJoystick(IN logical_rec_t * plr,
00237 IN vgfx::Primitive * obj,
00238 IN const char * logical,
00239 IN float x, IN float y);
00240 void setDpad(IN logical_rec_t * plr,
00241 IN vgfx::Primitive * obj,
00242 IN const char * logical,
00243 IN float x, IN float y);
00244
00245
00246 smart_ptr<vgfx::ObjectMap> m_objectMap;
00247 smart_ptr<vgfx::Drawer> m_drawer;
00248 vgfx::Primitive * m_vgfxRoot;
00249 vgfx::rect_t m_rect;
00250 Type * m_type;
00251 logical_map_t m_logicals;
00252 };
00253
00254
00255
00256 Renderer::Renderer
00257 (
00258 void
00259 )
00260 throw()
00261 {
00262 m_type = NULL;
00263 m_vgfxRoot = NULL;
00264 }
00265
00266
00267
00268 void
00269 Renderer::initialize
00270 (
00271 IN Type * type,
00272 IN smart_ptr<vgfx::Drawer>& drawer
00273 )
00274 {
00275 ASSERT(type, "null");
00276 ASSERT(drawer, "null");
00277 ASSERT(!m_type, "already have a type?");
00278 ASSERT(!m_drawer, "already have a drawer?");
00279 ASSERT(!m_vgfxRoot, "already have a root object?");
00280
00281 m_type = type;
00282 m_drawer = drawer;
00283
00284
00285 smart_ptr<nstream::Stream> vgfx = m_type->getVgfx();
00286 if (!vgfx) {
00287 DPRINTF("Type '%s' has no vector graphics object",
00288 m_type->getName());
00289 return;
00290 }
00291
00292
00293 m_objectMap = vgfx::ObjectMap::create();
00294 ASSERT(m_objectMap, "null");
00295
00296 std::istream& stream = vgfx->getStream();
00297 std::string undo, diagnostic;
00298 if (!vgfx::processRequest(m_objectMap, stream, false,
00299 undo, diagnostic)) {
00300 DPRINTF("ERROR PARSING VGFX FILE:\n%s", diagnostic.c_str());
00301 return;
00302 }
00303
00304
00305
00306 m_vgfxRoot = m_objectMap->findObject("root");
00307 if (!m_vgfxRoot) {
00308 DPRINTF("ERROR: vector graphics does not contain a root element");
00309 return;
00310 }
00311
00312
00313
00314 xform_2d_t T;
00315 T.setIdentity();
00316 m_vgfxRoot->recalcBoundingRect("*", m_drawer, T);
00317
00318
00319 m_vgfxRoot->getBoundingRect(m_rect);
00320
00321
00322
00323 VecString names;
00324 m_type->getAllInputs(names);
00325 for (VecString::const_iterator i = names.begin(); i != names.end();
00326 ++i) {
00327 const char * logical = i->c_str();
00328
00329 logical_rec_t lr;
00330 lr.baseColor.set(1, 1, 1, 1);
00331
00332 vgfx::Primitive * obj = m_objectMap->findObject(logical);
00333 if (!obj) {
00334 DPRINTF("ERROR: vgfx file is missing logical control: '%s",
00335 logical);
00336 } else {
00337 VecString path;
00338 path.push_back("meta");
00339 path.push_back("vgfxColor");
00340
00341 if (obj->doesContainerExist(path)) {
00342 dictionary_t data;
00343 obj->getContainerDictionary(path, data);
00344 const char * color =
00345 getOptionalValue(data, "vgfxColor", "");
00346
00347
00348 img_color_t ic;
00349 getImgColorFromString(color, ic);
00350 const float inv = 1.0 / 255.0;
00351 lr.baseColor.set(inv * ic.red, inv * ic.green,
00352 inv * ic.blue, inv * ic.alpha);
00353 } else {
00354
00355 }
00356 }
00357
00358
00359 m_logicals[logical] = lr;
00360 }
00361
00362 }
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372 void
00373 Renderer::setIntensity
00374 (
00375 IN const char * logical,
00376 IN float intensity
00377 )
00378 {
00379 ASSERT(logical, "null");
00380 ASSERT(intensity >= 0 && intensity <= 1,
00381 "Bad intensity: %f", intensity);
00382
00383
00384 logical_rec_t * plr = this->getLogical(logical);
00385 if (!plr)
00386 return;
00387
00388
00389 int iR = (int) (255.0 * intensity * plr->baseColor.red);
00390 int iG = (int) (255.0 * intensity * plr->baseColor.green);
00391 int iB = (int) (255.0 * intensity * plr->baseColor.blue);
00392 int iA = (int) (255.0 * plr->baseColor.alpha);
00393
00394 const int bufsize = 256;
00395 char buffer[bufsize];
00396 snprintf(buffer, bufsize, "r %d g %d b %d a %d", iR, iG, iB, iA);
00397
00398
00399
00400 dictionary_t data;
00401 data["vgfxColor"] = buffer;
00402
00403
00404 VecString path;
00405 path.push_back("meta");
00406 path.push_back("vgfxColor");
00407
00408 vgfx::Primitive * obj = m_objectMap->findObject(logical);
00409 if (!obj) {
00410 DPRINTF("No such object in vgfx file: '%s'", logical);
00411 return;
00412 }
00413
00414 obj->setContainerDictionary(path, data);
00415 }
00416
00417
00418
00419 void
00420 Renderer::setPosition
00421 (
00422 IN const char * logical,
00423 IN float x,
00424 IN float y
00425 )
00426 {
00427 ASSERT(logical, "null");
00428 ASSERT(x >= 0 && x <= 1, "bad x: %f", x);
00429 ASSERT(y >= 0 && y <= 1, "bad y: %f", y);
00430
00431
00432 logical_rec_t * plr = this->getLogical(logical);
00433 if (!plr)
00434 return;
00435
00436
00437 vgfx::Primitive * obj = m_objectMap->findObject(logical);
00438 if (!obj)
00439 return;
00440
00441 eInputType itype = m_type->getInputTypes(logical);
00442 if (eInput_Joystick & itype) {
00443 this->setJoystick(plr, obj, logical, x, y);
00444 } else if (eInput_Dpad & itype) {
00445 this->setDpad(plr, obj, logical, x, y);
00446 } else if (eInput_Pot & itype) {
00447
00448 } else {
00449
00450 }
00451 }
00452
00453
00454
00455 void
00456 Renderer::draw
00457 (
00458 IN int xOffset,
00459 IN int yOffset,
00460 IN int width,
00461 IN int height
00462 )
00463 {
00464 perf::Timer timer("TypeVgfx::draw");
00465 if (!m_vgfxRoot)
00466 return;
00467 ASSERT(m_drawer, "null");
00468
00469 float scaling = this->getScaling(width, height);
00470
00471 xform_2d_t translate;
00472 translate.setIdentity();
00473 translate.setTranslate(xOffset, yOffset);
00474
00475 xform_2d_t scale;
00476 scale.setTranslate(-m_rect.left, -m_rect.top);
00477 scale.scale(scaling);
00478
00479 xform_2d_t T;
00480 T.setToProductOf(translate, scale);
00481
00482 vgfx::rect_t r(xOffset, yOffset, xOffset + width, yOffset + height);
00483
00484
00485 m_vgfxRoot->draw(m_drawer, r, T);
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 float
00497 Renderer::getScaling
00498 (
00499 IN int width,
00500 IN int height
00501 )
00502 {
00503 ASSERT(width > 0, "bad width: %d", width);
00504 ASSERT(height > 0, "bad height: %d", height);
00505
00506 float cmX = m_rect.right - m_rect.left;
00507 float cmY = m_rect.bottom - m_rect.top;
00508
00509 float pixelsPerCmX = width / cmX;
00510 float pixelsPerCmY = height / cmY;
00511
00512 if (pixelsPerCmX > pixelsPerCmY) {
00513 return pixelsPerCmY;
00514 } else {
00515 return pixelsPerCmX;
00516 }
00517 }
00518
00519
00520
00521 Renderer::logical_rec_t *
00522 Renderer::getLogical
00523 (
00524 IN const char * logical
00525 )
00526 {
00527 ASSERT(logical, "null");
00528
00529 logical_map_t::iterator i = m_logicals.find(logical);
00530 if (m_logicals.end() == i) {
00531 return NULL;
00532 }
00533 return &i->second;
00534 }
00535
00536
00537
00538 void
00539 Renderer::setJoystick
00540 (
00541 IN logical_rec_t * plr,
00542 IN vgfx::Primitive * obj,
00543 IN const char * logical,
00544 IN float x,
00545 IN float y
00546 )
00547 {
00548 ASSERT(plr, "null");
00549 ASSERT(obj, "null");
00550 ASSERT(logical, "null");
00551 ASSERT(x >= 0 && x <= 1, "bad x: %f", x);
00552 ASSERT(y >= 0 && y <= 1, "bad y: %f", y);
00553
00554
00555
00556
00557 VecString path;
00558 path.push_back("object");
00559 path.push_back("pos");
00560 if (!obj->doesContainerExist(path))
00561 return;
00562
00563 x -= 0.5;
00564 y -= 0.5;
00565
00566 dictionary_t data;
00567 addFloat(data, "x", x);
00568 addFloat(data, "y", y);
00569
00570 obj->setContainerDictionary(path, data);
00571 }
00572
00573
00574
00575 void
00576 Renderer::setDpad
00577 (
00578 IN logical_rec_t * plr,
00579 IN vgfx::Primitive * obj,
00580 IN const char * logical,
00581 IN float x,
00582 IN float y
00583 )
00584 {
00585 ASSERT(plr, "null");
00586 ASSERT(obj, "null");
00587 ASSERT(logical, "null");
00588 ASSERT(x >= 0 && x <= 1, "bad x: %f", x);
00589 ASSERT(y >= 0 && y <= 1, "bad y: %f", y);
00590
00591 if (!m_vgfxRoot)
00592 return;
00593
00594
00595 xform_2d_t T;
00596 T.setIdentity();
00597 vgfx::visit_result_t vr;
00598 m_vgfxRoot->getPrimitive(logical, T, vr);
00599 if (!vr.p) {
00600 DPRINTF("Error: root object does not contain '%s'", logical);
00601 return;
00602 }
00603 vgfx::point_t p(0, 0);
00604 vgfx::point_t q = vr.T * p;
00605
00606
00607
00608 std::string name;
00609 if (!getField(m_objectMap, logical, "up", name)) {
00610 DPRINTF("Element '%s' does not contain 'up' meta field", logical);
00611 return;
00612 }
00613
00614
00615 std::string xName = logical;
00616 xName += "UpX";
00617 std::string yName = logical;
00618 yName += "UpY";
00619
00620
00621 if (x < 0.25) {
00622
00623 addOrMoveObject(m_objectMap, m_drawer, name.c_str(), xName.c_str(), q.x, q.y, -90);
00624 } else if (x > 0.75) {
00625
00626 addOrMoveObject(m_objectMap, m_drawer, name.c_str(), xName.c_str(), q.x, q.y, +90);
00627 } else {
00628
00629 removeObject(m_objectMap, xName.c_str());
00630 }
00631
00632
00633 if (y < 0.25) {
00634
00635 addOrMoveObject(m_objectMap, m_drawer, name.c_str(), yName.c_str(), q.x, q.y, +0);
00636 } else if (y > 0.75) {
00637
00638 addOrMoveObject(m_objectMap, m_drawer, name.c_str(), yName.c_str(), q.x, q.y, +180);
00639 } else {
00640
00641 removeObject(m_objectMap, yName.c_str());
00642 }
00643 }
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653 smart_ptr<TypeVgfxRenderer>
00654 TypeVgfxRenderer::create
00655 (
00656 IN Type * type,
00657 IN smart_ptr<vgfx::Drawer>& drawer
00658 )
00659 {
00660 ASSERT(type, "null");
00661 ASSERT(drawer, "null");
00662
00663 smart_ptr<Renderer> local = new Renderer;
00664 ASSERT(local, "out of memory");
00665
00666 local->initialize(type, drawer);
00667
00668 return local;
00669 }
00670
00671
00672
00673 };
00674