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 #include <SDL.h>
00026
00027
00028
00029
00030
00031
00032 #include "model/metamodel/grids/cellgrid.h"
00033 #include "model/metamodel/action.h"
00034 #include "model/metamodel/timeprovider.h"
00035 #include "model/structures/map.h"
00036 #include "model/structures/layer.h"
00037 #include "model/structures/instancetree.h"
00038 #include "model/structures/instance.h"
00039 #include "model/structures/location.h"
00040 #include "util/log/logger.h"
00041 #include "util/math/fife_math.h"
00042 #include "util/math/angles.h"
00043 #include "util/time/timemanager.h"
00044 #include "video/renderbackend.h"
00045 #include "video/image.h"
00046 #include "video/imagepool.h"
00047 #include "video/animation.h"
00048 #include "video/animationpool.h"
00049
00050 #include "camera.h"
00051 #include "visual.h"
00052
00053
00054 namespace FIFE {
00055 static Logger _log(LM_CAMERA);
00056
00057 Camera::Camera(const std::string& id,
00058 Layer *layer,
00059 const Rect& viewport,
00060 const ExactModelCoordinate& emc,
00061 RenderBackend* renderbackend,
00062 ImagePool* ipool,
00063 AnimationPool* apool):
00064 m_id(id),
00065 m_matrix(),
00066 m_inverse_matrix(),
00067 m_tilt(0),
00068 m_rotation(0),
00069 m_zoom(1),
00070 m_location(),
00071 m_prev_origo(ScreenPoint(0,0,0)),
00072 m_cur_origo(ScreenPoint(0,0,0)),
00073 m_viewport(),
00074 m_screen_cell_width(1),
00075 m_screen_cell_height(1),
00076 m_reference_scale(1),
00077 m_enabled(true),
00078 m_attachedto(NULL),
00079 m_image_dimensions(),
00080 m_iswarped(false),
00081 m_renderers(),
00082 m_pipeline(),
00083 m_updated(false),
00084 m_renderbackend(renderbackend),
00085 m_ipool(ipool),
00086 m_apool(apool),
00087 m_layer_to_instances() {
00088 m_location.setLayer(layer);
00089 m_location.setExactLayerCoordinates(emc);
00090 m_viewport = viewport;
00091 }
00092
00093 Camera::~Camera() {
00094 std::map<std::string, RendererBase*>::iterator r_it = m_renderers.begin();
00095 for(; r_it != m_renderers.end(); ++r_it) {
00096 delete r_it->second;
00097 }
00098 m_renderers.clear();
00099 }
00100
00101 void Camera::setTilt(double tilt) {
00102 m_tilt = tilt;
00103 updateReferenceScale();
00104 updateMatrices();
00105 m_iswarped = true;
00106 }
00107
00108 double Camera::getTilt() const {
00109 return m_tilt;
00110 }
00111
00112 void Camera::setRotation(double rotation) {
00113 m_rotation = rotation;
00114 updateReferenceScale();
00115 updateMatrices();
00116 m_iswarped = true;
00117 }
00118
00119 double Camera::getRotation() const {
00120 return m_rotation;
00121 }
00122
00123 void Camera::setZoom(double zoom) {
00124 m_zoom = zoom;
00125 if (m_zoom < 0.001) {
00126 m_zoom = 0.001;
00127 }
00128 updateMatrices();
00129 m_iswarped = true;
00130 }
00131
00132 double Camera::getZoom() const {
00133 return m_zoom;
00134 }
00135
00136 void Camera::setCellImageDimensions(unsigned int width, unsigned int height) {
00137 m_screen_cell_width = width;
00138 m_screen_cell_height = height;
00139 updateReferenceScale();
00140 updateMatrices();
00141 m_iswarped = true;
00142 }
00143
00144 void Camera::setLocation(const Location& location) {
00145
00146 if ((m_prev_origo == m_cur_origo) && (m_prev_origo == ScreenPoint(0,0,0))) {
00147 m_cur_origo = toScreenCoordinates(ExactModelCoordinate(0,0,0));
00148 m_prev_origo = m_cur_origo;
00149 }
00150 m_location = location;
00151
00152 CellGrid* cg = NULL;
00153 if (m_location.getLayer()) {
00154 cg = m_location.getLayer()->getCellGrid();
00155 } else {
00156 throw Exception("Location without layer given to Camera::setLocation");
00157 }
00158 if (!cg) {
00159 throw Exception("Camera layer has no cellgrid specified");
00160 }
00161
00162 updateMatrices();
00163
00164 m_cur_origo = toScreenCoordinates(ExactModelCoordinate(0,0,0));
00165 }
00166
00167 Point Camera::getCellImageDimensions() {
00168 return getCellImageDimensions(m_location.getLayer());
00169 }
00170
00171 Point Camera::getCellImageDimensions(Layer* layer) {
00172 if (layer == m_location.getLayer()) {
00173 return Point( m_screen_cell_width, m_screen_cell_height );
00174 }
00175 std::map<Layer*, Point>::iterator it = m_image_dimensions.find(layer);
00176 if (it != m_image_dimensions.end()) {
00177 return it->second;
00178 }
00179 Point p;
00180 CellGrid* cg = layer->getCellGrid();
00181 assert(cg);
00182 DoublePoint dimensions = getLogicalCellDimensions(layer);
00183 p.x = static_cast<int>(round(m_reference_scale * dimensions.x));
00184 p.y = static_cast<int>(round(m_reference_scale * dimensions.y));
00185 m_image_dimensions[layer] = p;
00186 return p;
00187 }
00188
00189 Location Camera::getLocation() const {
00190 return m_location;
00191 }
00192
00193 Location& Camera::getLocationRef() {
00194 return m_location;
00195 }
00196
00197 void Camera::setViewPort(const Rect& viewport) {
00198 m_viewport = viewport;
00199 }
00200
00201 const Rect& Camera::getViewPort() const {
00202 return m_viewport;
00203 }
00204
00205 void Camera::setEnabled(bool enabled) {
00206 m_enabled = enabled;
00207 }
00208
00209 bool Camera::isEnabled() {
00210 return m_enabled;
00211 }
00212
00213 void Camera::updateMatrices() {
00214 double scale = m_reference_scale;
00215 m_matrix.loadScale(scale, scale, scale);
00216 if (m_location.getLayer()) {
00217 CellGrid* cg = m_location.getLayer()->getCellGrid();
00218 if (cg) {
00219 ExactModelCoordinate pt = m_location.getMapCoordinates();
00220 m_matrix.applyTranslate( -pt.x *m_reference_scale,-pt.y *m_reference_scale, 0);
00221 }
00222 }
00223 scale = m_zoom;
00224 m_matrix.applyScale(scale, scale, scale);
00225 m_matrix.applyRotate(-m_rotation, 0.0, 0.0, 1.0);
00226 m_matrix.applyRotate(-m_tilt, 1.0, 0.0, 0.0);
00227 m_inverse_matrix = m_matrix.inverse();
00228 }
00229
00230 void Camera::calculateZValue(ScreenPoint& screen_coords) {
00231 int dy = -(screen_coords.y - toScreenCoordinates(m_location.getMapCoordinates()).y);
00232 screen_coords.z = static_cast<int>(tan(m_tilt * (M_PI / 180.0)) * static_cast<double>(dy));
00233 }
00234
00235 ExactModelCoordinate Camera::toMapCoordinates(ScreenPoint screen_coords, bool z_calculated) {
00236 if (!z_calculated) {
00237 calculateZValue(screen_coords);
00238 }
00239 screen_coords.x -= m_viewport.w / 2;
00240 screen_coords.y -= m_viewport.h / 2;
00241
00242 return m_inverse_matrix * intPt2doublePt(screen_coords);
00243 }
00244
00245 ScreenPoint Camera::toScreenCoordinates(ExactModelCoordinate elevation_coords) {
00246 ExactModelCoordinate p = elevation_coords;
00247 ScreenPoint pt = doublePt2intPt( m_matrix* p );
00248 pt.x += m_viewport.w / 2;
00249 pt.y += m_viewport.h / 2;
00250 return pt;
00251 }
00252
00253 DoublePoint Camera::getLogicalCellDimensions(Layer* layer) {
00254 CellGrid* cg = NULL;
00255 if (layer) {
00256 cg = layer->getCellGrid();
00257 }
00258 assert(cg);
00259
00260 ModelCoordinate cell(0,0);
00261 std::vector<ExactModelCoordinate> vertices;
00262 cg->getVertices(vertices, cell);
00263
00264 DoubleMatrix mtx;
00265 mtx.loadRotate(m_rotation, 0.0, 0.0, 1.0);
00266 mtx.applyRotate(m_tilt, 1.0, 0.0, 0.0);
00267 double x1, x2, y1, y2;
00268 for (unsigned int i = 0; i < vertices.size(); i++) {
00269 vertices[i] = cg->toMapCoordinates(vertices[i]);
00270 vertices[i] = mtx * vertices[i];
00271 if (i == 0) {
00272 x1 = x2 = vertices[0].x;
00273 y1 = y2 = vertices[0].y;
00274 } else {
00275 x1 = std::min(vertices[i].x, x1);
00276 x2 = std::max(vertices[i].x, x2);
00277 y1 = std::min(vertices[i].y, y1);
00278 y2 = std::max(vertices[i].y, y2);
00279 }
00280 }
00281 return DoublePoint( x2 - x1, y2 - y1 );
00282 }
00283
00284 void Camera::updateReferenceScale() {
00285 DoublePoint dim = getLogicalCellDimensions(m_location.getLayer());
00286 m_reference_scale = static_cast<double>(m_screen_cell_width) / dim.x;
00287
00288 FL_DBG(_log, "Updating reference scale");
00289 FL_DBG(_log, LMsg(" tilt=") << m_tilt << " rot=" << m_rotation);
00290 FL_DBG(_log, LMsg(" m_screen_cell_width=") << m_screen_cell_width);
00291 }
00292
00293 void Camera::getMatchingInstances(ScreenPoint screen_coords, Layer& layer, std::list<Instance*>& instances) {
00294 instances.clear();
00295 const std::vector<Instance*>& layer_instances = m_layer_to_instances[&layer];
00296 std::vector<Instance*>::const_iterator instance_it = layer_instances.end();
00297 while (instance_it != layer_instances.begin()) {
00298 --instance_it;
00299 Instance* i = (*instance_it);
00300 InstanceVisual* visual = i->getVisual<InstanceVisual>();
00301 InstanceVisualCacheItem& vc = visual->getCacheItem(this);
00302 if ((vc.dimensions.contains(Point(screen_coords.x, screen_coords.y)))) {
00303 assert(vc.image);
00304 Uint8 r, g, b, a;
00305 int x = screen_coords.x - vc.dimensions.x;
00306 int y = screen_coords.y - vc.dimensions.y;
00307 if (m_zoom != 1.0) {
00308 double fx = static_cast<double>(x);
00309 double fy = static_cast<double>(y);
00310 double fow = static_cast<double>(vc.image->getWidth());
00311 double foh = static_cast<double>(vc.image->getHeight());
00312 double fsw = static_cast<double>(vc.dimensions.w);
00313 double fsh = static_cast<double>(vc.dimensions.h);
00314 x = static_cast<int>(round(fx / fsw * fow));
00315 y = static_cast<int>(round(fy / fsh * foh));
00316 }
00317 vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
00318
00319 if (a != 0) {
00320 instances.push_back(i);
00321 }
00322 }
00323 }
00324 }
00325
00326 void Camera::getMatchingInstances(Rect screen_rect, Layer& layer, std::list<Instance*>& instances) {
00327 instances.clear();
00328 const std::vector<Instance*>& layer_instances = m_layer_to_instances[&layer];
00329 std::vector<Instance*>::const_iterator instance_it = layer_instances.end();
00330 while (instance_it != layer_instances.begin()) {
00331 --instance_it;
00332 Instance* i = (*instance_it);
00333 InstanceVisual* visual = i->getVisual<InstanceVisual>();
00334 InstanceVisualCacheItem& vc = visual->getCacheItem(this);
00335 if ((vc.dimensions.intersects(screen_rect))) {
00336 assert(vc.image);
00337 Uint8 r, g, b, a;
00338 for(int xx = screen_rect.x; xx < screen_rect.x + screen_rect.w; xx++) {
00339 for(int yy = screen_rect.y; yy < screen_rect.y + screen_rect.h; yy++) {
00340 if ((vc.dimensions.contains(Point(xx, yy)))) {
00341 int x = xx - vc.dimensions.x;
00342 int y = yy - vc.dimensions.y;
00343 if (m_zoom != 1.0) {
00344 double fx = static_cast<double>(x);
00345 double fy = static_cast<double>(y);
00346 double fow = static_cast<double>(vc.image->getWidth());
00347 double foh = static_cast<double>(vc.image->getHeight());
00348 double fsw = static_cast<double>(vc.dimensions.w);
00349 double fsh = static_cast<double>(vc.dimensions.h);
00350 x = static_cast<int>(round(fx / fsw * fow));
00351 y = static_cast<int>(round(fy / fsh * foh));
00352 }
00353 vc.image->getPixelRGBA(x, y, &r, &g, &b, &a);
00354
00355 if (a != 0) {
00356 instances.push_back(i);
00357 goto found_non_transparent_pixel;
00358 }
00359 }
00360 }
00361 }
00362 found_non_transparent_pixel:;
00363 }
00364 }
00365 }
00366
00367 void Camera::getMatchingInstances(Location& loc, std::list<Instance*>& instances, bool use_exactcoordinates) {
00368 instances.clear();
00369 const std::vector<Instance*>& layer_instances = m_layer_to_instances[loc.getLayer()];
00370 std::vector<Instance*>::const_iterator instance_it = layer_instances.end();
00371 while (instance_it != layer_instances.begin()) {
00372 --instance_it;
00373 Instance* i = (*instance_it);
00374 if (use_exactcoordinates) {
00375 if (i->getLocationRef().getExactLayerCoordinatesRef() == loc.getExactLayerCoordinatesRef()) {
00376 instances.push_back(i);
00377 }
00378 } else {
00379 if (i->getLocationRef().getLayerCoordinates() == loc.getLayerCoordinates()) {
00380 instances.push_back(i);
00381 }
00382 }
00383 }
00384 }
00385
00386 void Camera::attach(Instance *instance) {
00387
00388 if (m_location.getLayer()->getId() != instance->getLocation().getLayer()->getId()) {
00389 FL_WARN(_log, "Tried to attach camera to instance on different layer.");
00390 return ;
00391 }
00392 m_attachedto = instance;
00393 }
00394
00395 void Camera::detach() {
00396 m_attachedto = NULL;
00397 }
00398
00399 void Camera::update() {
00400 if( !m_attachedto ) {
00401 return;
00402 }
00403 Location loc(m_location);
00404 loc.setExactLayerCoordinates( m_attachedto->getLocationRef().getExactLayerCoordinates(m_location.getLayer()) );
00405 setLocation(loc);
00406 updateMatrices();
00407 }
00408
00409 void Camera::refresh() {
00410 updateMatrices();
00411 m_iswarped = true;
00412 }
00413
00414 void Camera::resetUpdates() {
00415 m_iswarped = false;
00416 m_prev_origo = m_cur_origo;
00417 }
00418
00419 bool pipelineSort(const RendererBase* lhs, const RendererBase* rhs) {
00420 return (lhs->getPipelinePosition() < rhs->getPipelinePosition());
00421 }
00422
00423 void Camera::addRenderer(RendererBase* renderer) {
00424 renderer->setRendererListener(this);
00425 m_renderers[renderer->getName()] = renderer;
00426 if (renderer->isEnabled()) {
00427 m_pipeline.push_back(renderer);
00428 }
00429 m_pipeline.sort(pipelineSort);
00430 }
00431
00432 void Camera::onRendererPipelinePositionChanged(RendererBase* renderer) {
00433 m_pipeline.sort(pipelineSort);
00434 }
00435
00436 void Camera::onRendererEnabledChanged(RendererBase* renderer) {
00437 assert(m_renderers[renderer->getName()]);
00438 if (renderer->isEnabled()) {
00439 FL_LOG(_log, LMsg("Enabling renderer ") << renderer->getName());
00440 m_pipeline.push_back(renderer);
00441 m_pipeline.sort(pipelineSort);
00442 } else {
00443 m_pipeline.remove(renderer);
00444 }
00445 }
00446
00447 RendererBase* Camera::getRenderer(const std::string& name) {
00448 return m_renderers[name];
00449 }
00450
00451 class InstanceDistanceSort {
00452 public:
00453 Camera* cam;
00454 inline bool operator()(const Instance* lhs, const Instance* rhs) {
00455 InstanceVisual* liv = lhs->getVisual<InstanceVisual>();
00456 InstanceVisual* riv = rhs->getVisual<InstanceVisual>();
00457 InstanceVisualCacheItem& lic = liv->getCacheItem(cam);
00458 InstanceVisualCacheItem& ric = riv->getCacheItem(cam);
00459 if (lic.screenpoint.z == ric.screenpoint.z) {
00460 return liv->getStackPosition() < riv->getStackPosition();
00461 }
00462 return lic.screenpoint.z < ric.screenpoint.z;
00463 }
00464 };
00465
00466 void Camera::resetRenderers() {
00467 std::map<std::string, RendererBase*>::iterator r_it = m_renderers.begin();
00468 for (; r_it != m_renderers.end(); ++r_it) {
00469 Map* map = m_location.getMap();
00470 r_it->second->reset();
00471 }
00472 }
00473
00474 void Camera::render() {
00475 ScreenPoint cammove = m_prev_origo - m_cur_origo;
00476
00477 Map* map = m_location.getMap();
00478 if (!map) {
00479 FL_ERR(_log, "No map for camera found");
00480 return;
00481 }
00482
00483
00484
00485
00486
00487 m_renderbackend->pushClipArea(getViewPort());
00488
00489 m_layer_to_instances.clear();
00490
00491 const std::list<Layer*>& layers = map->getLayers();
00492 std::list<Layer*>::const_iterator layer_it = layers.begin();
00493 for (;layer_it != layers.end(); ++layer_it) {
00494
00495
00496
00497
00498
00499 const std::vector<Instance*>& allinstances = (*layer_it)->getInstances();
00500 std::vector<Instance*>::const_iterator instance_it = allinstances.begin();
00501 std::vector<Instance*>& instances_to_render = m_layer_to_instances[*layer_it];
00502 for (;instance_it != allinstances.end(); ++instance_it) {
00503 Instance* instance = *instance_it;
00504 InstanceVisual* visual = instance->getVisual<InstanceVisual>();
00505 if(!visual->isVisible())
00506 continue;
00507 InstanceVisualCacheItem& vc = visual->getCacheItem(this);
00508
00509
00510 ScreenPoint drawpt;
00511 int angle = 0;
00512 if (m_updated && (!m_iswarped) && (!(instance->getChangeInfo() & (ICHANGE_LOC | ICHANGE_ROTATION | ICHANGE_FACING_LOC))) && (vc.image)) {
00513 int pos_estimate_x = vc.screenpoint.x - cammove.x;
00514 int pos_estimate_y = vc.screenpoint.y - cammove.y;
00515 int pos_estimate_z = vc.screenpoint.z - cammove.z;
00516 angle = vc.facing_angle;
00517
00518
00519 drawpt.x = pos_estimate_x;
00520 drawpt.y = pos_estimate_y;
00521 drawpt.z = pos_estimate_z;
00522
00523 } else {
00524 drawpt = toScreenCoordinates( instance->getLocationRef().getMapCoordinates() );
00525 vc.facing_angle = getAngleBetween(instance->getLocationRef(), instance->getFacingLocation());
00526 angle = vc.facing_angle;
00527 }
00528
00529
00530 angle = angle + m_rotation + instance->getRotation();
00531
00532 Image* image = NULL;
00533 Action* action = instance->getCurrentAction();
00534 if (action) {
00535 FL_DBG(_log, "Instance has action");
00536 int animation_id = action->getVisual<ActionVisual>()->getAnimationIndexByAngle(vc.facing_angle + m_rotation);
00537
00538 int facing_angle = vc.facing_angle;
00539 if (facing_angle < 0){
00540 facing_angle = 360+facing_angle;
00541 }
00542 facing_angle %= 360;
00543 instance->setRotation(facing_angle);
00544
00545 Animation& animation = m_apool->getAnimation(animation_id);
00546 unsigned int animtime = instance->getActionRuntime() % animation.getDuration();
00547 image = animation.getFrameByTimestamp(animtime);
00548 } else {
00549 FL_DBG(_log, "No action");
00550 int imageid = vc.getStaticImageIndexByAngle(angle, instance);
00551 FL_DBG(_log, LMsg("Instance does not have action, using static image with id ") << imageid);
00552 if (imageid >= 0) {
00553 image = &m_ipool->getImage(imageid);
00554 } else {
00555
00556 action = instance->getObject()->getDefaultAction();
00557 if (action) {
00558 int animation_id = action->getVisual<ActionVisual>()->getAnimationIndexByAngle(angle);
00559 Animation& animation = m_apool->getAnimation(animation_id);
00560 unsigned int animtime = instance->getActionRuntime() % animation.getDuration();
00561 image = animation.getFrameByTimestamp(animtime);
00562 }
00563 }
00564 }
00565 if (image) {
00566 vc.image = image;
00567 vc.screenpoint = drawpt;
00568
00569 int w = image->getWidth();
00570 int h = image->getHeight();
00571 drawpt.x -= w / 2;
00572 drawpt.x += image->getXShift();
00573 drawpt.y -= h / 2;
00574 drawpt.y += image->getYShift();
00575 Rect r = Rect(drawpt.x, drawpt.y, w, h);
00576
00577 vc.dimensions = r;
00578 if (m_zoom != 1.0) {
00579
00580
00581
00582 r.w = static_cast<unsigned int>(ceil(static_cast<double>(vc.dimensions.w) * m_zoom)) + 2;
00583 r.h = static_cast<unsigned int>(ceil(static_cast<double>(vc.dimensions.h) * m_zoom)) + 2;
00584 int xo = static_cast<int>(ceil(static_cast<double>(vc.image->getXShift()) * m_zoom)) - vc.image->getXShift();
00585 int yo = static_cast<int>(ceil(static_cast<double>(vc.image->getYShift()) * m_zoom)) - vc.image->getYShift();
00586 r.x = vc.dimensions.x - static_cast<unsigned int>(ceil(static_cast<double>(r.w - vc.dimensions.w) / 2)) + xo - 1;
00587 r.y = vc.dimensions.y - static_cast<unsigned int>(ceil(static_cast<double>(r.h - vc.dimensions.h) / 2)) + yo - 1;
00588 vc.dimensions = r;
00589 }
00590
00591 if (vc.dimensions.intersects(getViewPort())) {
00592 instances_to_render.push_back(instance);
00593 }
00594 }
00595 }
00596
00597 InstanceDistanceSort ids;
00598 ids.cam = this;
00599 std::stable_sort(instances_to_render.begin(), instances_to_render.end(), ids);
00600
00601 std::list<RendererBase*>::iterator r_it = m_pipeline.begin();
00602 for (; r_it != m_pipeline.end(); ++r_it) {
00603 if ((*r_it)->isActivedLayer(*layer_it)) {
00604 (*r_it)->render(this, *layer_it, instances_to_render);
00605 }
00606 }
00607 }
00608 m_renderbackend->popClipArea();
00609 resetUpdates();
00610 m_updated = true;
00611 }
00612
00613 }