diff options
Diffstat (limited to 'layoutgl')
-rw-r--r-- | layoutgl/texturemanager.cpp | 31 | ||||
-rw-r--r-- | layoutgl/texturemanager.h | 33 | ||||
-rw-r--r-- | layoutgl/widget.cpp | 389 | ||||
-rw-r--r-- | layoutgl/widget.h | 53 |
4 files changed, 506 insertions, 0 deletions
diff --git a/layoutgl/texturemanager.cpp b/layoutgl/texturemanager.cpp new file mode 100644 index 0000000..80a8186 --- /dev/null +++ b/layoutgl/texturemanager.cpp @@ -0,0 +1,31 @@ +#include "texturemanager.h" + +LGLTextureManager::LGLTextureManager() { +} + +void LGLTextureManager::setup(QGLWidget *gl, const LYTLayout *layout) { + // TODO: code to cleanup previous stuff + + //m_gl = gl; + m_layout = layout; + m_package = &layout->package(); + + QStringList textures = layout->generateTextureRefs(); + + foreach (const QString &texName, textures) { + qDebug() << texName; + + QByteArray tplData = m_package->getTexture(texName); + + QDataStream tplStream(tplData); + WiiTexPalette tpl(tplStream); + + const QImage &image = tpl.textures.first().image; + image.save(QString("tpl/%2__%1.png").arg(texName).arg((int)tpl.textures.first().format)); + // dirty, dirty hack, TODO: FIXME + GLuint tex = gl->bindTexture(image, GL_TEXTURE_2D); + + m_textures.insert(texName, tex); + m_images.insert(texName, image); + } +} diff --git a/layoutgl/texturemanager.h b/layoutgl/texturemanager.h new file mode 100644 index 0000000..07b7739 --- /dev/null +++ b/layoutgl/texturemanager.h @@ -0,0 +1,33 @@ +#ifndef TEXTUREMANAGER_H +#define TEXTUREMANAGER_H + +#include "wii/texpalette.h" +#include "lyt/layout.h" +#include <QGLContext> +#include <QHash> + +class LGLTextureManager { +public: + LGLTextureManager(); + + void setup(QGLWidget *gl, const LYTLayout *layout); + +private: + const QGLContext *m_gl; + const LYTLayout *m_layout; + const LYTPackageBase *m_package; + + QHash<QString, GLuint> m_textures; + QHash<QString, QImage> m_images; + +public: + GLuint glTextureForName(const QString name) const { + return m_textures.value(name); + } + + QImage imageForName(const QString name) const { + return m_images.value(name); + } +}; + +#endif // TEXTUREMANAGER_H diff --git a/layoutgl/widget.cpp b/layoutgl/widget.cpp new file mode 100644 index 0000000..0758e88 --- /dev/null +++ b/layoutgl/widget.cpp @@ -0,0 +1,389 @@ +#include "widget.h" + +LGLWidget::LGLWidget(QWidget *parent) : + QGLWidget(parent), m_layout(0) { +} + + +void LGLWidget::setLayout(LYTLayout *layout) { + // TODO: cleanup stuff for previous layout + + m_layout = layout; + setFixedSize(layout->width, layout->height); +} + + +void LGLWidget::initializeGL() { + qDebug() << "initialising GL"; + glClearColor(0.0, 0.0, 0.0, 0.0); + glEnable(GL_TEXTURE_2D); + + // this makes texture transparency work + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // makes glColor value blend with textures + glEnable(GL_COLOR_MATERIAL); + + m_texMgr.setup(this, m_layout); +} + + +void LGLWidget::resizeGL(int w, int h) { + glViewport(0, 0, (GLint)w, (GLint)h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-304, 304, -228, 228, -100, 100); + glMatrixMode(GL_MODELVIEW); +} + + +void LGLWidget::paintGL() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (m_layout == 0) + return; + + glLoadIdentity(); + + renderPane(m_layout->rootPane); +} + +void LGLWidget::renderPane(const LYTPane *pane) { + glPushMatrix(); + + glScalef(pane->xScale, pane->yScale, 1.0f); + glRotatef(pane->xRot, 1.0f, 0.0f, 0.0f); + glRotatef(pane->yRot, 0.0f, 1.0f, 0.0f); + glRotatef(pane->zRot, 0.0f, 0.0f, 1.0f); + glTranslatef(pane->xTrans, pane->yTrans, pane->zTrans); + //qDebug() << "Translating by" << pane->xTrans << pane->yTrans << pane->zTrans; + + switch (pane->type()) { + case LYTPane::PictureType: + drawPicture((LYTPicture*)pane); + break; + case LYTPane::WindowType: + drawWindow((LYTWindow*)pane); + break; + } + + foreach (const LYTPane *childPane, pane->children) + renderPane(childPane); + + //qDebug() << "Popping"; + glPopMatrix(); +} + +void LGLWidget::drawPicture(const LYTPicture *pic) { + float dX = pic->drawnVertexX(); + float dY = pic->drawnVertexY(); + //qDebug() << "Drawing" << dX << dY << pic->width << pic->height; + + useMaterial(pic->materialName); + + drawQuad(dX, dY, pic->width, pic->height, pic->texCoords, pic->vtxColours, pic->alpha); + + glColor3ub(255, 255, 255); + renderText(dX, (dY-pic->height)+10, 0, pic->name); +} + +struct TexFlipBit { + quint8 bits[8]; + quint8 one, two; +}; + +static const TexFlipBit TextureFlipInfo[6] = { + {{0,0,1,0,0,1,1,1},0,1}, + {{1,0,0,0,1,1,0,1},0,1}, + {{0,1,1,1,0,0,1,0},0,1}, + {{0,1,0,0,1,1,1,0},1,0}, + {{1,1,0,1,1,0,0,0},0,1}, + {{1,0,1,1,0,0,0,1},1,0} +}; + +void LGLWidget::dealWithWindowFrame(LYTTexCoords &coords, const QString &materialName, + int flipType, float pieceWidth, float pieceHeight, + int rep1, int rep2, int rep3, int rep4) { + // What are you DOING Nintendo.. the code for this is a mess! + // I seriously don't get it. + // I am also using a terrible hack here. + const TexFlipBit &info = TextureFlipInfo[flipType]; + + qreal *hack = (qreal*)(&coords.coord[0]); + + float assign1 = info.bits[rep1 + info.one]; + hack[rep1 + info.one] = assign1; + hack[rep3 + info.one] = assign1; + + float assign2 = info.bits[rep1 + info.two]; + hack[rep1 + info.two] = assign2; + hack[rep2 + info.two] = assign2; + + float texSize[2]; + getTextureSize(materialName, &texSize[0], &texSize[1]); + + float assign3 = info.bits[rep1 + info.one] + (pieceWidth / ((info.bits[rep2 + info.one] - info.bits[rep1 + info.one]) * texSize[info.one])); + hack[rep2 + info.one] = assign3; + hack[rep4 + info.one] = assign3; + + float assign4 = info.bits[rep1 + info.two] + (pieceHeight / ((info.bits[rep3 + info.two] - info.bits[rep1 + info.two]) * texSize[info.two])); + hack[rep3 + info.two] = assign4; + hack[rep4 + info.two] = assign4; +} + +void LGLWidget::drawWindow(const LYTWindow *wnd) { + float dX = wnd->drawnVertexX(); + float dY = wnd->drawnVertexY(); + + // get the frame size + float frameLeft, frameTop, frameRight, frameBottom; + + switch (wnd->frames.count()) { + case 1: + float oneW, oneH; + getTextureSize(wnd->frames.at(0)->materialName, &oneW, &oneH); + frameLeft = frameRight = oneW; + frameTop = frameBottom = oneH; + break; + case 4: case 8: + getTextureSize(wnd->frames.at(0)->materialName, &frameLeft, &frameTop); + getTextureSize(wnd->frames.at(3)->materialName, &frameRight, &frameBottom); + break; + } + + // draw the content + useMaterial(wnd->contentMaterialName); + qDebug() << "content material:" << wnd->contentMaterialName; + drawQuad( + dX + frameLeft - wnd->contentOverflowLeft, + dY - frameTop + wnd->contentOverflowTop, + ((wnd->contentOverflowLeft + (wnd->width - frameLeft)) - frameRight) + wnd->contentOverflowRight, + ((wnd->contentOverflowTop + (wnd->height - frameTop)) - frameBottom) + wnd->contentOverflowBottom, + wnd->contentTexCoords, wnd->contentVtxColours, wnd->alpha); + + // deal with the frame + LYTTexCoords texCoords; + + switch (wnd->frames.count()) { + case 1: + { + const LYTWindowFrame &frame = *wnd->frames.first(); + const LYTMaterial &mat = getMaterial(frame.materialName); + + if (!mat.texMaps.empty()) { + useMaterial(mat); + + // top left + float pieceWidth = wnd->width - frameRight; + float pieceHeight = frameTop; + + dealWithWindowFrame(texCoords, frame.materialName, 0, pieceWidth, pieceHeight, 0, 2, 4, 6); + drawQuad(dX, dY, pieceWidth, pieceHeight, 1, &texCoords, 0, wnd->alpha); + + // top right + pieceWidth = frameRight; + pieceHeight = wnd->height - frameBottom; + + dealWithWindowFrame(texCoords, frame.materialName, 1, pieceWidth, pieceHeight, 2, 0, 6, 4); + + drawQuad(dX + wnd->width - frameRight, dY, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + + // bottom left + pieceWidth = frameLeft; + pieceHeight = wnd->height - frameTop; + + dealWithWindowFrame(texCoords, frame.materialName, 2, pieceWidth, pieceHeight, 4, 6, 0, 2); + + drawQuad(dX, dY - frameTop, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + + // bottom right + pieceWidth = wnd->width - frameLeft; + pieceHeight = frameBottom; + + dealWithWindowFrame(texCoords, frame.materialName, 4, pieceWidth, pieceHeight, 6, 4, 2, 0); + + drawQuad(dX + frameLeft, dY - wnd->height + frameBottom, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + } + } + break; + case 4: + { + // top left + const LYTWindowFrame &fTL = *wnd->frames.at(0); + const LYTMaterial &mTL = getMaterial(fTL.materialName); + + if (!mTL.texMaps.empty()) { + useMaterial(mTL); + + float pieceWidth = wnd->width - frameRight; + float pieceHeight = frameTop; + + dealWithWindowFrame(texCoords, fTL.materialName, fTL.type, pieceWidth, pieceHeight, 0, 2, 4, 6); + drawQuad(dX, dY, pieceWidth, pieceHeight, 1, &texCoords, 0, wnd->alpha); + } + + // top right + const LYTWindowFrame &fTR = *wnd->frames.at(1); + const LYTMaterial &mTR = getMaterial(fTR.materialName); + + if (!mTR.texMaps.empty()) { + useMaterial(mTR); + + float pieceWidth = frameRight; + float pieceHeight = wnd->height - frameBottom; + + dealWithWindowFrame(texCoords, fTR.materialName, fTR.type, pieceWidth, pieceHeight, 2, 0, 6, 4); + + drawQuad(dX + wnd->width - frameRight, dY, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + } + + // bottom left + const LYTWindowFrame &fBL = *wnd->frames.at(2); + const LYTMaterial &mBL = getMaterial(fBL.materialName); + + if (!mBL.texMaps.empty()) { + useMaterial(mBL); + + float pieceWidth = frameLeft; + float pieceHeight = wnd->height - frameTop; + + dealWithWindowFrame(texCoords, fBL.materialName, fBL.type, pieceWidth, pieceHeight, 4, 6, 0, 2); + + drawQuad(dX, dY - frameTop, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + } + + const LYTWindowFrame &fBR = *wnd->frames.at(3); + const LYTMaterial &mBR = getMaterial(fBR.materialName); + + // bottom right + if (!mBR.texMaps.empty()) { + useMaterial(mBR); + + float pieceWidth = frameRight; + float pieceHeight = wnd->height - frameBottom; + + dealWithWindowFrame(texCoords, fBR.materialName, fBR.type, pieceWidth, pieceHeight, 6, 4, 0, 2); + + drawQuad(dX + frameLeft, dY - wnd->height + frameBottom, pieceWidth, pieceHeight, + 1, &texCoords, 0, wnd->alpha); + } + } + break; + default: + qDebug() << "unhandled window frame count" << wnd->frames.count(); + } +} + +static GLint GLWrapModes[] = { + GL_CLAMP_TO_EDGE, // Clamp + GL_REPEAT, // Repeat + GL_MIRRORED_REPEAT, // Mirror +}; + +void LGLWidget::useMaterial(const QString &materialName) { + const LYTMaterial *mat = m_layout->materials.getMaterialByName(materialName); + + useMaterial(*mat); +} + +void LGLWidget::useMaterial(const LYTMaterial &mat) { + int cutAt = mat.texMaps.count(); + + for (int i = 0; i < cutAt; i++) { + const LYTTexMap &texMap = mat.texMaps.at(i); + + const QString &texName = texMap.textureName; + GLuint texID = m_texMgr.glTextureForName(texName); + + glActiveTexture(GL_TEXTURE0 + i); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLWrapModes[texMap.wrap_s]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLWrapModes[texMap.wrap_t]); + + // is there a matching TexSRT? + // TODO: fix this + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + if (mat.texSRTs.count() > i) { + const LYTTexSRT &srt = mat.texSRTs.at(i); + + glScalef(srt.xScale, srt.yScale, 1.0f); + // rotate? + glTranslatef(srt.xTrans, -srt.yTrans, 0.0f); + } + + glMatrixMode(GL_MODELVIEW); + } + + for (int i = cutAt; i < 8; i++) { + glActiveTexture(GL_TEXTURE0 + i); + glDisable(GL_TEXTURE_2D); + } + + glActiveTexture(GL_TEXTURE0); +} + +void LGLWidget::drawQuad(float x, float y, float w, float h, const QVector<LYTTexCoords> &texCoords, const QColor *colours, uchar alpha) { + drawQuad(x, y, w, h, texCoords.count(), texCoords.constData(), colours, alpha); +} + +void LGLWidget::drawQuad(float x, float y, float w, float h, int texCoordCount, const LYTTexCoords *texCoords, const QColor *colours, uchar alpha) { + if (!colours) + glColor4ub(255, 255, 255, 255); + + glBegin(GL_QUADS); + + for (int i = 0; i < texCoordCount; i++) + glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[0].x(), 1.0f-texCoords[i].coord[0].y()); + + if (colours) + qglColor(colours[0]); + glVertex2f(x, y); + + for (int i = 0; i < texCoordCount; i++) + glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[1].x(), 1.0f-texCoords[i].coord[1].y()); + + if (colours) + qglColor(colours[1]); + glVertex2f(x + w, y); + + for (int i = 0; i < texCoordCount; i++) + glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[3].x(), 1.0f-texCoords[i].coord[3].y()); + + if (colours) + qglColor(colours[2]); + glVertex2f(x + w, y - h); + + for (int i = 0; i < texCoordCount; i++) + glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[2].x(), 1.0f-texCoords[i].coord[2].y()); + + if (colours) + qglColor(colours[3]); + glVertex2f(x, y - h); + + glEnd(); +} + + +void LGLWidget::getTextureSize(const QString &materialName, float *w, float *h) { + const LYTMaterial *mat = m_layout->materials.getMaterialByName(materialName); + + if (mat->texMaps.count() == 0) { + *w = 0.0f; + *h = 0.0f; + } else { + const LYTTexMap &tm = mat->texMaps.first(); + + QImage img = m_texMgr.imageForName(tm.textureName); + *w = img.width(); + *h = img.height(); + } +} + diff --git a/layoutgl/widget.h b/layoutgl/widget.h new file mode 100644 index 0000000..e6abdfc --- /dev/null +++ b/layoutgl/widget.h @@ -0,0 +1,53 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include <QGLWidget> + +#include "lyt/layout.h" +#include "layoutgl/texturemanager.h" + +class LGLWidget : public QGLWidget +{ + Q_OBJECT +public: + explicit LGLWidget(QWidget *parent = 0); + + void setLayout(LYTLayout *layout); + +protected: + void initializeGL(); + void resizeGL(int w, int h); + void paintGL(); + + LYTLayout *m_layout; + + void renderPane(const LYTPane *pane); + + void drawPicture(const LYTPicture *pic); + void drawWindow(const LYTWindow *wnd); + + const LYTMaterial &getMaterial(const QString &materialName) { + return *m_layout->materials.getMaterialByName(materialName); + } + + void useMaterial(const QString &materialName); + void useMaterial(const LYTMaterial &material); + + void drawQuad(float x, float y, float w, float h, const QVector<LYTTexCoords> &texCoords, const QColor *colours, uchar alpha); + void drawQuad(float x, float y, float w, float h, int texCoordCount, const LYTTexCoords *texCoords, const QColor *colours, uchar alpha); + + void getTextureSize(const QString &materialName, float *w, float *h); + + void dealWithWindowFrame(LYTTexCoords &coords, const QString &materialName, int flipType, + float pieceWidth, float pieceHeight, + int rep1, int rep2, int rep3, int rep4); + + LGLTextureManager m_texMgr; + +signals: + +public slots: + +}; + +#endif // WIDGET_H |