Skip to content

Gfx Tools

Gfx is the new graphics engine I helped develop with a team of ten people. The engine uses custom OpenGL for 2D and some portions of Open Scene Graph for 3D. The tools are written in C++ and Qt. I was the unofficial leader of tools development. I wrote the majority of the tools, especially the prototypes. Further polishing of the tools was done by several other developers, especially the ones requesting or supporting the tools.

Some screenshots of various tools:

This is the 2D/3D content tool. The artists export an FBX from Max and import into a scene in this tool. Users can modify textures, materials, lights, and other assets. A P3D file is exported after processing lossy compressed textures, pre-generated mipmaps, and other data processing. Probably the most complicated part to write was the property editor. You’d be surprised how difficult it is to write a robust and reusable property editor system that looks good and is easy to use.

GfxAnimationTool is a replacement for JASC Animation Shop which the artists had been using for years but were unsatisfied with. This is a feature rich tool for generating, building, and playing 2D animations. I designed this app to be as close to JASC as possible but with more modern design elements and workflow. One major advantage of a custom tool like this is the artists can make requests and receive updates regularly. The workflow and features are tailored to their needs.

GfxPackTool generates binary data package files for use in 2D. The game developer writes a javascript file that tells the tool the files to load and how to process them. The screenshot below shows the content browser from an existing package file. I did not design this tool, this is an evolution, and probably the 5th rewrite, of a simple texture processing tool. 

GfxTextureViewer is a simple viewer for textures and various data formats. It can also play animations such as MNGs and Binks. Nearly every other tool incorporates the viewer in one way or another. This tool has evolved quite a bit from its humble origin as a simple texture viewer.

GfxConsole is a remote debugging tool as well as a way to load test modules without the need to write a full blown game. With the tool, the developer or tester can see memory mapping and usage, scene hierarchy, loaded textures and assets, performance meters, and log output.

/**
 * Initializes the property editor after cloning.
 *
 * @param   Editor  parent editor
 * @param   Name    name of property widget
 * @param   Indent  amount of space to indent
 */
void ImagePropertyWidget::initialize(
    PropertyEditorWidget&    Editor,
    const QString&           Name,
    u32                      Indent )
{
    PropertyWidget::initialize(Editor,Name,Indent);

    QHBoxLayout* layout = new QHBoxLayout();
    {
        gfxDeref(layout).setSpacing(0);
        gfxDeref(layout).setContentsMargins(0,0,0,0);

        QVBoxLayout* left = new QVBoxLayout;
        {
            gfxDeref(left).setSpacing(0);
            gfxDeref(left).setContentsMargins(0,0,0,0);

            if (Editor.getUseIconsForNonCategory())
                gfxDeref(left).addLayout(createLabel(this,QIcon(":/propertyeditor/icons/image.png")));
            else
                gfxDeref(left).addLayout(createLabel(this));

            _dimensionsLabel = new QLabel(this);
            gfxDeref(left).addWidget(_dimensionsLabel,0,Qt::AlignHCenter | Qt::AlignVCenter);

            _depthLabel = new QLabel(this);
            gfxDeref(left).addWidget(_depthLabel,0,Qt::AlignHCenter | Qt::AlignVCenter);

            _zoomLabel = new QLabel(this);
            gfxDeref(left).addWidget(_zoomLabel,0,Qt::AlignHCenter | Qt::AlignVCenter);

            gfxDeref(left).addStretch(1);
        }
        gfxDeref(layout).addLayout(left,1);

        QHBoxLayout* right = new QHBoxLayout;
        {
            gfxDeref(right).setSpacing(0);
            gfxDeref(right).setContentsMargins(0,0,0,0);

            _zoomImageLabel = new QLabel(this);
            gfxDeref(right).addWidget(_zoomImageLabel,1);

            QVBoxLayout* column_layout = new QVBoxLayout;
            {
                gfxDeref(column_layout).setSpacing(0);
                gfxDeref(column_layout).setContentsMargins(0,0,0,0);

                // first button row
                QHBoxLayout* row_layout1 = new QHBoxLayout;
                {
                    gfxDeref(row_layout1).setSpacing(0);
                    gfxDeref(row_layout1).setContentsMargins(0,0,0,0);

                    gfxDeref(row_layout1).addStretch(1);

                    _zoom_in = new PropertyButton(this,QIcon(":/propertyeditor/icons/zoom_in.png"),QIcon());
                    gfxDeref(_zoom_in).setToolTip("Zoom In");
                    connect(_zoom_in,SIGNAL(clicked()),this,SLOT(onZoomIn()));
                    gfxDeref(row_layout1).addWidget(_zoom_in,0,Qt::AlignTop);

                    _zoom_out = new PropertyButton(this,QIcon(":/propertyeditor/icons/zoom_out.png"),QIcon());
                    gfxDeref(_zoom_out).setToolTip("Zoom Out");
                    connect(_zoom_out,SIGNAL(clicked()),this,SLOT(onZoomOut()));
                    gfxDeref(row_layout1).addWidget(_zoom_out,0,Qt::AlignTop);

                    _zoom_reset = new PropertyButton(this,QIcon(":/propertyeditor/icons/zoom_reset.png"),QIcon());
                    gfxDeref(_zoom_reset).setToolTip("Reset zoom level");
                    connect(_zoom_reset,SIGNAL(clicked()),this,SLOT(onZoomReset()));
                    gfxDeref(row_layout1).addWidget(_zoom_reset,0,Qt::AlignTop);
                }
                gfxDeref(column_layout).addLayout(row_layout1);

                // second button row
                QHBoxLayout* row_layout2 = new QHBoxLayout;
                {
                    gfxDeref(row_layout2).setSpacing(0);
                    gfxDeref(row_layout2).setContentsMargins(0,0,0,0);

                    gfxDeref(row_layout2).addStretch(1);

                    _eye = new PropertyButton(this,QIcon(":/propertyeditor/icons/eye.png"),QIcon());
                    gfxDeref(_eye).setToolTip("Open texture viewer");
                    connect(_eye,SIGNAL(clicked()),this,SLOT(onEye()));
                    gfxDeref(row_layout2).addWidget(_eye,0,Qt::AlignTop);
                }
                gfxDeref(column_layout).addLayout(row_layout2);

                gfxDeref(column_layout).addStretch(1);
            }
            gfxDeref(right).addLayout(column_layout);
        }
        gfxDeref(layout).addLayout(right,2);
    }
    addRowLayout(gfxDeref(layout));
}