/* * SpriteView.cpp * toycars_vehicle_editor * * Created by Ruben Henner Zilibowitz on 23/02/09. * Copyright 2009 Ruben Henner Zilibowitz. All rights reserved. * */ #include "SpriteView.h" #include "FL/Fl_Image.H" #include #include #include "LoadSpriteFromImage.h" #include "ScException.h" #include #include "SearchDirectories.h" extern SearchDirectories *gSearchDirs; SpriteView::SpriteView(int x,int y,int w,int h,const char *l) : Fl_Gl_Window(x,y,w,h,l), vehicleSprite(NULL), wheelSprite(NULL), rotation(0), steerAngle(0), scale(2), o(NULL), setting(kNoSetting), mouseIsDown(false), mouseIsInside(false), convexChoice(0), mouseConvexity(true) { } SpriteView::~SpriteView() { if (vehicleSprite) delete vehicleSprite; if (wheelSprite) delete wheelSprite; } int SpriteView::handle(int event) { if (event == FL_PUSH) { if (setting == kGeometry) { if (!o->getGeometry()->empty()) { std::list &curConvex = (*o->getGeometry())[convexChoice]; if (Fl::event_button() == FL_LEFT_MOUSE && mouseConvexity) curConvex.push_back(Vec2D(mousex,mousey)); else if (Fl::event_button() == FL_RIGHT_MOUSE && !curConvex.empty()) curConvex.pop_back(); } } mouseIsDown = true; redraw(); return 1; } else if (event == FL_DRAG) { redraw(); return 1; } else if (event == FL_RELEASE) { mouseIsDown = false; redraw(); return 1; } else if (event == FL_ENTER) { mouseIsInside = true; redraw(); return 1; } else if (event == FL_MOVE) { redraw(); return 1; } else if (event == FL_LEAVE) { mouseIsInside = false; redraw(); return 1; } return Fl_Gl_Window::handle(event); } bool angleReflexive(const Vec2D &A, const Vec2D &B, const Vec2D &C) { Vec2D X(A.x - B.x, A.y - B.y); Vec2D Y(C.x - B.x, C.y - B.y); return X.x*Y.y - X.y*Y.x >= 0; } bool checkConvexity(const std::list &convex, Vec2D mouse) { if (convex.size() <= 2) return true; std::list::const_iterator A = convex.end(); A--; std::list::const_iterator B = A; A--; std::list::const_iterator C = convex.begin(); std::list::const_iterator D = C; D++; // A,B,mouse if (angleReflexive(*A, *B, mouse)) return false; // B,mouse,C if (angleReflexive(*B, mouse, *C)) return false; // mouse,C,D if (angleReflexive(mouse, *C, *D)) return false; return true; } void SpriteView::draw() { if (!valid()) { glLoadIdentity(); glViewport(0,0,w(),h()); glOrtho(0,w(),0,h(),-1,1); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(1,1,1,1); } // load the vehicle sprite from the file is not loaded if (!(o->getVehicleSpriteFilename()[0] == '\0' || vehicleSprite)) { ScSprite *sprite; try { sprite = loadSpriteFromImage(o->getVehicleSpriteFilename(), o->getVehicleFrameWidth(), o->getVehicleFrameHeight(), gSearchDirs); } catch (ScException e) { e.printMsg(); fl_alert("Error loading vehicle sprite."); return; } if (sprite == NULL) return; vehicleSprite = sprite; } // load the wheel sprite from the file is not loaded if (!(o->getWheelSpriteFilename()[0] == '\0' || wheelSprite)) { ScSprite *sprite; try { sprite = loadSpriteFromImage(o->getWheelSpriteFilename(), o->getWheelFrameWidth(), o->getWheelFrameHeight(), gSearchDirs); } catch (ScException e) { e.printMsg(); fl_alert("Error loading wheel sprite."); return; } if (sprite == NULL) return; wheelSprite = sprite; } // draw sprites glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); glTranslated((w() - o->getVehicleFrameWidth()*scale)*0.5, (h() - o->getVehicleFrameHeight()*scale)*0.5, 0); glScaled(scale, scale, 1); if (o->getWheelsAboveSprite()) { drawVehicleSprite(); drawWheelsSprites(); } else { drawWheelsSprites(); drawVehicleSprite(); } glPopMatrix(); // draw edit guides mousex = (-w()*0.5 + Fl::event_x() - x()) / scale; mousey = (h()*0.5 - Fl::event_y() + y()) / scale; glDisable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_1D); glPushMatrix(); glTranslated(w()*0.5, h()*0.5, 0); glRotated(rotation*360, 0, 0, 1); glScaled(scale, scale, 1); const int geomSize = o->getGeometry()->size(); switch (setting) { case kGeometry: mouseConvexity = true; for (int i = 0; i < geomSize; i++) { glBegin(GL_LINE_LOOP); glColor3d(1,0,0); const std::list &l = (*o->getGeometry())[i]; for (std::list::const_iterator it = l.begin(); it != l.end(); it++) glVertex2d(it->x, it->y); glEnd(); } if (geomSize > 0 && mouseIsInside) { const std::list &curConvex = (*o->getGeometry())[convexChoice]; if (!curConvex.empty()) { mouseConvexity = checkConvexity(curConvex, Vec2D(mousex,mousey)); if (mouseConvexity) glColor3d(0,1,0); else glColor3d(1,0,0); glBegin(GL_LINES); glVertex2d(curConvex.back().x, curConvex.back().y); glVertex2d(mousex, mousey); glVertex2d(mousex, mousey); glVertex2d(curConvex.front().x, curConvex.front().y); glEnd(); } } break; case kAxelWidth: if (!mouseIsInside && !mouseIsDown) mousey = o->getAxelWidth()*0.5; glBegin(GL_LINES); glColor3d(1, 0, 0); glVertex2d(o->getFrontAxel(), 0); glVertex2d(o->getFrontAxel(), mousey); glColor3d(0, 1, 0); glVertex2d(-o->getRearAxel(), 0); glVertex2d(-o->getRearAxel(), mousey); glEnd(); if (mouseIsDown) { settingInput->value(mousey*2); o->setAxelWidth(settingInput->value()); } break; case kFrontAxel: if (!mouseIsInside && !mouseIsDown) mousex = o->getFrontAxel(); glBegin(GL_LINES); glColor3d(1, 0, 0); glVertex2d(0, 0); glVertex2d(mousex, 0); glColor3d(0, 1, 0); glVertex2d(mousex, -o->getAxelWidth()*0.5); glVertex2d(mousex, o->getAxelWidth()*0.5); glEnd(); if (mouseIsDown) { settingInput->value(mousex); o->setFrontAxel(settingInput->value()); } break; case kRearAxel: if (!mouseIsInside && !mouseIsDown) mousex = -o->getRearAxel(); glBegin(GL_LINES); glColor3d(1, 0, 0); glVertex2d(0, 0); glVertex2d(mousex, 0); glColor3d(0, 1, 0); glVertex2d(mousex, -o->getAxelWidth()*0.5); glVertex2d(mousex, o->getAxelWidth()*0.5); glEnd(); if (mouseIsDown) { settingInput->value(-mousex); o->setRearAxel(settingInput->value()); } break; case kFrontWheelInset: if (!mouseIsInside && !mouseIsDown) mousey = o->getFrontWheelInset(); glBegin(GL_LINES); // right wheel glColor3d(0, 1, 0); glVertex2d(o->getFrontAxel() - o->getFrontWheelRadius(), -o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + o->getFrontWheelRadius(), -o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + o->getFrontWheelRadius(), -o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + o->getFrontWheelRadius(), -o->getAxelWidth()*0.5 + mousey); glVertex2d(o->getFrontAxel() - o->getFrontWheelRadius(), -o->getAxelWidth()*0.5 + mousey); glVertex2d(o->getFrontAxel() - o->getFrontWheelRadius(), -o->getAxelWidth()*0.5); glColor3d(1, 0, 0); glVertex2d(o->getFrontAxel() + o->getFrontWheelRadius(), -o->getAxelWidth()*0.5 + mousey); glVertex2d(o->getFrontAxel() - o->getFrontWheelRadius(), -o->getAxelWidth()*0.5 + mousey); // left wheel glColor3d(0, 1, 0); glVertex2d(o->getFrontAxel() - o->getFrontWheelRadius(), o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + o->getFrontWheelRadius(), o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + o->getFrontWheelRadius(), o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + o->getFrontWheelRadius(), o->getAxelWidth()*0.5 - mousey); glVertex2d(o->getFrontAxel() - o->getFrontWheelRadius(), o->getAxelWidth()*0.5 - mousey); glVertex2d(o->getFrontAxel() - o->getFrontWheelRadius(), o->getAxelWidth()*0.5); glColor3d(1, 0, 0); glVertex2d(o->getFrontAxel() + o->getFrontWheelRadius(), o->getAxelWidth()*0.5 - mousey); glVertex2d(o->getFrontAxel() - o->getFrontWheelRadius(), o->getAxelWidth()*0.5 - mousey); glEnd(); if (mouseIsDown) { settingInput->value(mousey); o->setFrontWheelInset(settingInput->value()); } break; case kFrontWheelRadius: if (!mouseIsInside && !mouseIsDown) mousex = o->getFrontWheelRadius(); else mousex -= o->getFrontAxel(); glBegin(GL_LINES); // right wheel glColor3d(0, 1, 0); glVertex2d(o->getFrontAxel() - mousex, -o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + mousex, -o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + mousex, -o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + mousex, -o->getAxelWidth()*0.5 + o->getFrontWheelInset()); glVertex2d(o->getFrontAxel() - mousex, -o->getAxelWidth()*0.5 + o->getFrontWheelInset()); glVertex2d(o->getFrontAxel() - mousex, -o->getAxelWidth()*0.5); glColor3d(1, 0, 0); glVertex2d(o->getFrontAxel() + mousex, -o->getAxelWidth()*0.5 + o->getFrontWheelInset()); glVertex2d(o->getFrontAxel() - mousex, -o->getAxelWidth()*0.5 + o->getFrontWheelInset()); // left wheel glColor3d(0, 1, 0); glVertex2d(o->getFrontAxel() - mousex, o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + mousex, o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + mousex, o->getAxelWidth()*0.5); glVertex2d(o->getFrontAxel() + mousex, o->getAxelWidth()*0.5 - o->getFrontWheelInset()); glVertex2d(o->getFrontAxel() - mousex, o->getAxelWidth()*0.5 - o->getFrontWheelInset()); glVertex2d(o->getFrontAxel() - mousex, o->getAxelWidth()*0.5); glColor3d(1, 0, 0); glVertex2d(o->getFrontAxel() + mousex, o->getAxelWidth()*0.5 - o->getFrontWheelInset()); glVertex2d(o->getFrontAxel() - mousex, o->getAxelWidth()*0.5 - o->getFrontWheelInset()); glEnd(); if (mouseIsDown) { settingInput->value(fabs(mousex)); o->setFrontWheelRadius(settingInput->value()); } break; case kRearWheelRadius: if (!mouseIsInside && !mouseIsDown) mousex = o->getRearWheelRadius(); else mousex += o->getRearAxel(); glBegin(GL_LINES); // right wheel glColor3d(0, 1, 0); glVertex2d(-o->getRearAxel() - mousex, -o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() + mousex, -o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() + mousex, -o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() + mousex, -o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() - mousex, -o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() - mousex, -o->getAxelWidth()*0.5); glColor3d(1, 0, 0); glVertex2d(-o->getRearAxel() + mousex, -o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() - mousex, -o->getAxelWidth()*0.5); // left wheel glColor3d(0, 1, 0); glVertex2d(-o->getRearAxel() - mousex, o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() + mousex, o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() + mousex, o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() + mousex, o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() - mousex, o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() - mousex, o->getAxelWidth()*0.5); glColor3d(1, 0, 0); glVertex2d(-o->getRearAxel() + mousex, o->getAxelWidth()*0.5); glVertex2d(-o->getRearAxel() - mousex, o->getAxelWidth()*0.5); glEnd(); if (mouseIsDown) { settingInput->value(fabs(mousex)); o->setRearWheelRadius(settingInput->value()); } break; } glPopMatrix(); glDisable(GL_TEXTURE_1D); glEnable(GL_TEXTURE_2D); } void SpriteView::reset() { if (vehicleSprite) { delete vehicleSprite; vehicleSprite = NULL; } if (wheelSprite) { delete wheelSprite; wheelSprite = NULL; } rotation = 0; steerAngle = 0; scale = 2; redraw(); } void SpriteView::resetVehicleSprite() { if (vehicleSprite) { delete vehicleSprite; vehicleSprite = NULL; } redraw(); } void SpriteView::resetWheelSprite() { if (wheelSprite) { delete wheelSprite; wheelSprite = NULL; } redraw(); } void SpriteView::drawVehicleSprite() { if (vehicleSprite) { vehicleSprite->setFrame(fmod(vehicleSprite->getNumFrames()*rotation, vehicleSprite->getNumFrames())); vehicleSprite->doDraw(); } } void SpriteView::drawWheelsSprites() { if (wheelSprite) { double x, y; glPushMatrix(); x = o->getFrontAxel(); y = o->getAxelWidth()*0.5 - o->getFrontWheelInset(); glTranslated(x*cos(rotation*2*M_PI) - y*sin(rotation*2*M_PI) + (o->getVehicleFrameWidth() - o->getWheelFrameWidth())*0.5 , x*sin(rotation*2*M_PI) + y*cos(rotation*2*M_PI) + (o->getVehicleFrameHeight() - o->getWheelFrameHeight())*0.5, 0); wheelSprite->setFrame(fmod(wheelSprite->getNumFrames() + wheelSprite->getNumFrames() * (steerAngle + rotation), wheelSprite->getNumFrames())); wheelSprite->doDraw(); glPopMatrix(); glPushMatrix(); x = o->getFrontAxel(); y = -o->getAxelWidth()*0.5 + o->getFrontWheelInset(); glTranslated(x*cos(rotation*2*M_PI) - y*sin(rotation*2*M_PI) + (o->getVehicleFrameWidth() - o->getWheelFrameWidth())*0.5 , x*sin(rotation*2*M_PI) + y*cos(rotation*2*M_PI) + (o->getVehicleFrameHeight() - o->getWheelFrameHeight())*0.5, 0); wheelSprite->setFrame(fmod(wheelSprite->getNumFrames() + wheelSprite->getNumFrames() * (steerAngle + rotation + 0.5), wheelSprite->getNumFrames())); wheelSprite->doDraw(); glPopMatrix(); } }