/* * Copyright (c) 2002-2006 Samit Basu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "QTRenderEngine.hpp" #include #include #include bool operator<(const quad3d& a, const quad3d& b) { return (a.meanz < b.meanz); } void cross(double ux, double uy, double uz, double vx, double vy, double vz, double &sx, double &sy, double &sz) { sx = uy*vz-uz*vy; sy = uz*vx-ux*vz; sz = ux*vy-uy*vx; } QTRenderEngine::QTRenderEngine(QPainter *painter, double x1, double y1, double width, double height) { pnt = painter; pnt->setRenderHint(QPainter::TextAntialiasing); m_x1 = x1; m_y1 = y1; m_width = width; m_height = height; inDirect = false; pnt->setPen(QColor(0,0,0)); pnt->setBrush(QColor(0,0,0)); debugFlag = false; } QTRenderEngine::~QTRenderEngine() { } void QTRenderEngine::clear(std::vector col) { pnt->save(); pnt->setPen(QColor((int)(col[0]*255),(int)(col[1]*255),(int)(col[2]*255))); pnt->setBrush(QColor((int)(col[0]*255),(int)(col[1]*255),(int)(col[2]*255))); pnt->drawRect((int)m_x1,(int)m_y1,(int)m_width,(int)m_height); pnt->restore(); } QPointF QTRenderEngine::Map(double x, double y, double z) { double a, b; toPixels(x,y,z,a,b); b = m_height-1-b; return QPointF(rint(a),rint(b)); } QVector QTRenderEngine::Map(std::vector xs, std::vector ys, std::vector zs) { QVector retval; for (int i=0;i QTRenderEngine::MapQuadsFacesOnly(std::vector > &faces) { std::vector retval; for (int i=0;i qlist(faces[i]); for (int j=2;j QTRenderEngine::MapQuadsEdgesOnly(std::vector > &edges) { std::vector retval; for (int i=0;i elist(edges[i]); for (int j=2;j QTRenderEngine::MapQuads(std::vector > &faces, std::vector > &edges) { std::vector retval; if (edges.size() == 0) return MapQuadsFacesOnly(faces); if (faces.size() == 0) return MapQuadsEdgesOnly(edges); for (int i=0;i qlist(faces[i]); std::vector elist(edges[i]); for (int j=2;j 1) | (yclip < -1) | (yclip > 1) | (zclip < -1) | (zclip > 1)); a = viewp[0] + (1+xclip)/2.0*viewp[2]; b = viewp[1] + (1+yclip)/2.0*viewp[3]; } void QTRenderEngine::toPixels(double x, double y, double z, double &a, double &b, double &c, bool &clipped) { double xprime, yprime, zprime, wprime; double xclip, yclip, zclip, wclip; wprime = 1; mapPoint(x,y,z,xprime,yprime,zprime); xclip = proj[0]*xprime + proj[4]*yprime + proj[8]*zprime + proj[12]; yclip = proj[1]*xprime + proj[5]*yprime + proj[9]*zprime + proj[13]; zclip = proj[2]*xprime + proj[6]*yprime + proj[10]*zprime + proj[14]; wclip = proj[3]*xprime + proj[7]*yprime + proj[11]*zprime + proj[15]; xclip /= wclip; yclip /= wclip; zclip /= wclip; clipped = ((xclip < -1) | (xclip > 1) | (yclip < -1) | (yclip > 1) | (zclip < -1) | (zclip > 1)); a = viewp[0] + (1+xclip)/2.0*viewp[2]; b = viewp[1] + (1+yclip)/2.0*viewp[3]; c = zclip; } void QTRenderEngine::lookAt(double eyex, double eyey, double eyez, double centerx, double centery, double centerz, double upx, double upy, double upz) { double fx, fy, fz; fx = centerx - eyex; fy = centery - eyey; fz = centerz - eyez; double fnorm = sqrt(fx*fx+fy*fy+fz*fz); fx /= fnorm; fy /= fnorm; fz /= fnorm; double upnorm = sqrt(upx*upx+upy*upy+upz*upz); upx /= upnorm; upy /= upnorm; upz /= upnorm; double sx, sy, sz; cross(fx,fy,fz,upx,upy,upz,sx,sy,sz); double ux, uy, uz; cross(sx,sy,sz,fx,fy,fz,ux,uy,uz); model[0] = sx; model[4] = sy; model[8] = sz; model[12] = -eyex; model[1] = ux; model[5] = uy; model[9] = uz; model[13] = -eyey; model[2] =-fx; model[6] =-fy; model[10]=-fz; model[14]= -eyez; model[3] = 0; model[7] = 0; model[11] = 0; model[15] = 1; } void QTRenderEngine::scale(double sx, double sy, double sz) { model[0] *= sx; model[4] *= sy; model[8] *= sz; model[1] *= sx; model[5] *= sy; model[9] *= sz; model[2] *= sx; model[6] *= sy; model[10] *= sz; model[3] *= sx; model[7] *= sy; model[11] *= sz; } void QTRenderEngine::mapPoint(double x, double y, double z, double &a, double &b, double &c) { a = model[0]*x + model[4]*y + model[8]*z + model[12]; b = model[1]*x + model[5]*y + model[9]*z + model[13]; c = model[2]*x + model[6]*y + model[10]*z + model[14]; } void QTRenderEngine::project(double left, double right, double bottom, double top, double near, double far) { double tx, ty, tz; tx = -(right+left)/(right-left); ty = -(top+bottom)/(top-bottom); tz = -(far+near)/(far-near); for (int i=0;i<16;i++) proj[i] = 0; proj[0] = 2/(right-left); proj[5] = 2/(top-bottom); proj[10] = -2/(far-near); proj[12] = tx; proj[13] = ty; proj[14] = tz; // proj[15] = -1; proj[15] = 1; // To match GL // if (left != 0) // qDebug("Project %f %f %f %f %f %f",left,right,bottom,top,near,far); } void QTRenderEngine::viewport(double x0, double y0, double width, double height) { viewp[0] = (int)x0; viewp[1] = (int)y0; viewp[2] = (int)width; viewp[3] = (int)height; pnt->setClipRect((int)x0,(int)(m_height-(y0+height)),(int)width,(int)height); // qDebug() << "clip " << x0 << "," << (int)(m_height-(y0+height)) << "," << (int)width << "," << (int)height; } void QTRenderEngine::quad(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3, double x4, double y4, double z4) { QPolygonF poly; poly.push_back(Map(x1,y1,z1)); poly.push_back(Map(x2,y2,z2)); poly.push_back(Map(x3,y3,z3)); poly.push_back(Map(x4,y4,z4)); pnt->drawPolygon(poly); } void QTRenderEngine::quadline(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3, double x4, double y4, double z4) { QPolygonF poly; poly.push_back(Map(x1,y1,z1)); poly.push_back(Map(x2,y2,z2)); poly.push_back(Map(x3,y3,z3)); poly.push_back(Map(x4,y4,z4)); poly.push_back(Map(x1,y1,z1)); pnt->drawPolyline(poly); } void QTRenderEngine::tri(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3) { QPolygonF poly; poly.push_back(Map(x1,y1,z1)); poly.push_back(Map(x2,y2,z2)); poly.push_back(Map(x3,y3,z3)); pnt->drawPolygon(poly); } void QTRenderEngine::triLine(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3) { QPolygonF poly; poly.push_back(Map(x1,y1,z1)); poly.push_back(Map(x2,y2,z2)); poly.push_back(Map(x3,y3,z3)); pnt->drawPolyline(poly); } void QTRenderEngine::color(std::vector col) { QPen pen(pnt->pen()); QBrush brush(pnt->brush()); pen.setColor(QColor((int)(col[0]*255),(int)(col[1]*255),(int)(col[2]*255))); brush.setColor(QColor((int)(col[0]*255),(int)(col[1]*255),(int)(col[2]*255))); pnt->setPen(pen); pnt->setBrush(brush); } void QTRenderEngine::setLineStyle(std::string style) { QPen pen(pnt->pen()); if (style == "-") pen.setStyle(Qt::SolidLine); else if (style == "--") pen.setStyle(Qt::DashLine); else if (style == ":") pen.setStyle(Qt::DotLine); else if (style == "-.") pen.setStyle(Qt::DashDotLine); else if (style == "none") pen.setStyle(Qt::NoPen); pnt->setPen(pen); } void QTRenderEngine::lineWidth(double n) { QPen pen(pnt->pen()); pen.setWidthF(n); pnt->setPen(pen); } void QTRenderEngine::line(double x1, double y1, double z1, double x2, double y2, double z2) { pnt->drawLine(Map(x1,y1,z1),Map(x2,y2,z2)); } void QTRenderEngine::line(double x1, double y1, double x2, double y2) { pnt->drawLine(Map(x1,y1,0),Map(x2,y2,0)); } void QTRenderEngine::lineSeries(std::vector xs, std::vector ys, std::vector zs) { if (xs.size() < 2) return; pnt->drawPolyline(Map(xs,ys,zs)); } void QTRenderEngine::debug() { debugFlag = !debugFlag; // qDebug("Projection diagonal: %f %f %f %f", // proj[0],proj[5],proj[10],proj[15]); return; // qDebug("QT Modelview matrix (before setupdirect)"); // qDebug("%f %f %f %f",model[0],model[4],model[8],model[12]); // qDebug("%f %f %f %f",model[1],model[5],model[9],model[13]); // qDebug("%f %f %f %f",model[2],model[6],model[10],model[14]); // qDebug("%f %f %f %f",model[3],model[7],model[11],model[15]); // qDebug("QT Projection matrix (before setupdirect)"); // qDebug("%f %f %f %f",proj[0],proj[4],proj[8],proj[12]); // qDebug("%f %f %f %f",proj[1],proj[5],proj[9],proj[13]); // qDebug("%f %f %f %f",proj[2],proj[6],proj[10],proj[14]); // qDebug("%f %f %f %f",proj[3],proj[7],proj[11],proj[15]); // qDebug("QT Viewport (before setupdirect)"); // qDebug("%d %d %d %d",viewp[0],viewp[1],viewp[2],viewp[3]); } void QTRenderEngine::setupDirectDraw() { // if (inDirect) // qDebug("DirectDraw is not reentrant!!!"); // save the relevant matrices for (int i=0;i<16;i++) { save_model[i] = model[i]; model[i] = 0; save_proj[i] = proj[i]; } for (int i=0;i<4;i++) save_viewp[i] = viewp[i]; model[0] = 1; model[5] = 1; model[10] = 1; model[15] = 1; viewport(m_x1,m_y1,m_width,m_height); project(m_x1,m_x1+m_width,m_y1,m_y1+m_height,-1,1); inDirect = true; } void QTRenderEngine::releaseDirectDraw() { // if (!inDirect) // qDebug("releaseDirectDraw called unmatched!!!"); for (int i=0;i<16;i++) { model[i] = save_model[i]; proj[i] = save_proj[i]; } for (int i=0;i<4;i++) viewp[i] = save_viewp[i]; inDirect = false; } void QTRenderEngine::getProjectionMatrix(double aproj[16]) { for (int i=0;i<16;i++) aproj[i] = proj[16]; } void QTRenderEngine::getModelviewMatrix(double amodel[16]) { for (int i=0;i<16;i++) amodel[i] = model[i]; } void QTRenderEngine::getViewport(int aviewp[4]) { for (int i=0;i<4;i++) aviewp[i] = viewp[i]; } void QTRenderEngine::putText(double x, double y, std::string txt, std::vector color, AlignmentFlag xflag, AlignmentFlag yflag, QFont fnt, double rotation) { QFontMetrics fm(fnt); QRect sze(fm.boundingRect(txt.c_str())); int x0 = sze.left(); int y0 = sze.bottom(); int width = sze.width(); int height = sze.height(); // Adjust the raster position based on the alignment offsets double xdelta, ydelta; xdelta = 0; ydelta = 0; if (xflag == Mean) xdelta = -width/2.0; if (xflag == Max) xdelta = -width; if (yflag == Mean) ydelta = -height/2.0; if (yflag == Max) ydelta = -height; // I don't understand this... #ifdef WIN32 ydelta += fm.descent(); #endif #ifdef __APPLE__ ydelta += fm.descent(); #endif double costhet, sinthet; costhet = cos(rotation*M_PI/180.0); sinthet = sin(rotation*M_PI/180.0); double xpos, ypos; xpos = x+xdelta*costhet-ydelta*sinthet; ypos = y+xdelta*sinthet+ydelta*costhet; QPointF pos(Map(xpos,ypos,0)); QPen pen(pnt->pen()); pnt->setPen(QColor((int)(color[0]*255),(int)(color[1]*255),(int)(color[2]*255))); pnt->setFont(fnt); pnt->save(); pnt->translate(pos); pnt->rotate(-rotation); pnt->drawText(0,0,txt.c_str()); pnt->restore(); pnt->setPen(pen); } void QTRenderEngine::measureText(std::string txt, QFont fnt, AlignmentFlag xflag, AlignmentFlag yflag,int &width, int &height, int &xoffset, int &yoffset) { QFontMetrics fm(fnt); QRect sze(fm.boundingRect(txt.c_str())); width = sze.width(); height = sze.height(); yoffset = -height; xoffset = 0; if (xflag == Mean) xoffset -= width/2; else if (xflag == Max) xoffset -= width; if (yflag == Mean) yoffset += height/2; else if (yflag == Min) yoffset += height; } void QTRenderEngine::depth(bool) { } void QTRenderEngine::rect(double x1, double y1, double x2, double y2) { quadline(x1,y1,0, x2,y1,0, x2,y2,0, x1,y2,0); } void QTRenderEngine::rectFill(double x1, double y1, double x2, double y2) { quad(x1,y1,0, x2,y1,0, x2,y2,0, x1,y2,0); } void QTRenderEngine::circle(double x1, double y1, double radius) { QPointF uleft(Map(x1-radius,y1+radius,0)); QPointF lright(Map(x1+radius,y1-radius,0)); QRectF rect; rect.setBottomRight(lright); rect.setTopLeft(uleft); QBrush brsh(pnt->brush()); pnt->setBrush(Qt::NoBrush); pnt->drawEllipse(rect); pnt->setBrush(brsh); } void QTRenderEngine::circleFill(double x1, double y1, double radius) { QPointF uleft(Map(x1-radius,y1+radius,0)); QPointF lright(Map(x1+radius,y1-radius,0)); QRectF rect; rect.setBottomRight(lright); rect.setTopLeft(uleft); QPen pen(pnt->pen()); pnt->setPen(Qt::NoPen); pnt->drawEllipse(rect); pnt->setPen(pen); } void QTRenderEngine::drawImage(double x1, double y1, double x2, double y2, QImage pic) { QPointF pt(Map(x1,y1,0)); pt.setY(pt.y()-pic.height()); // qDebug() << "image draw at " << pt << "," << pic.size(); pnt->drawImage(pt,pic); } QPainterPath QTRenderEngine::quadToPoly(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3, double x4, double y4, double z4) { QPainterPath path; path.moveTo(Map(x1,y1,z1)); path.lineTo(Map(x2,y2,z2)); path.lineTo(Map(x3,y3,z3)); path.lineTo(Map(x4,y4,z4)); path.closeSubpath(); return path; } void QTRenderEngine::setClipBox(std::vector limits) { pnt->setClipPath(quadToPoly( limits[0], limits[2], limits[4], limits[1], limits[2], limits[4], limits[1], limits[3], limits[4], limits[0], limits[3], limits[4]), Qt::ReplaceClip); pnt->setClipPath(quadToPoly( limits[0], limits[2], limits[5], limits[0], limits[3], limits[5], limits[1], limits[3], limits[5], limits[1], limits[2], limits[5]), Qt::UniteClip); pnt->setClipPath(quadToPoly( limits[0], limits[2], limits[4], limits[0], limits[3], limits[4], limits[0], limits[3], limits[5], limits[0], limits[2], limits[5]), Qt::UniteClip); pnt->setClipPath(quadToPoly( limits[1], limits[2], limits[4], limits[1], limits[2], limits[5], limits[1], limits[3], limits[5], limits[1], limits[3], limits[4]), Qt::UniteClip); pnt->setClipPath(quadToPoly( limits[0], limits[2], limits[4], limits[0], limits[2], limits[5], limits[1], limits[2], limits[5], limits[1], limits[2], limits[4]), Qt::UniteClip); pnt->setClipPath(quadToPoly( limits[0], limits[3], limits[4], limits[1], limits[3], limits[4], limits[1], limits[3], limits[5], limits[0], limits[3], limits[5]), Qt::UniteClip); // pnt->setClipPath(path); } void QTRenderEngine::quadStrips(std::vector > faces, bool flatfaces, std::vector > edges, bool flatedges) { // qDebug() << "Faces " << faces.size(); // qDebug() << "Edges " << edges.size(); std::vector mapqds(MapQuads(faces,edges)); std::sort(mapqds.begin(),mapqds.end()); for (int i=0;isetBrush(QColor((int)(mapqds[i].r*255), (int)(mapqds[i].g*255), (int)(mapqds[i].b*255), (int)(mapqds[i].a*255))); pnt->setPen(QColor((int)(mapqds[i].er*255),(int)(mapqds[i].eg*255), (int)(mapqds[i].eb*255),(int)(mapqds[i].ea*255))); pnt->drawPolygon(poly); } } //};