Test Code/TinselTest.c

/******************************************************************************
 **                                                                          **
 **     Module:     TinselTest.c                                             **
 **                                                                          **
 **     Purpose:    Main file for Tinsel Town test app                       **
 **                                                                          **
 **     Author:     Mike W. Kelley                                           **
 **                                                                          **
 **                 2/3/95  Revised for 0.9 SDK release                      **
 **                                                                          **
 **     Copyright (C) 1994-95 Apple Computer, Inc.  All rights reserved.     **
 **                                                                          **
 *****************************************************************************/
 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
/* Macintosh */
#include <Types.h>
#include <QuickDraw.h>
#include <Windows.h>
 
/* Project */
#include "RAVE.h"
#include "TinselTest.h"
 
/*******************************************************************************************
 *
 * Defines that affect how the tests are run.
 *
 ******************************************************************************************/
 
 #define dWaitForButton     /* If defined, wait for button click between tests */
 
/*******************************************************************************************
 *
 * Declare the registration function for the empty rasterizer. This allows us to call
 * it from our app, so we can link the rasterizer in instead of using a shared library.
 *
 ******************************************************************************************/
 
extern OSErr TtRegister (void);
 
/*******************************************************************************************
 *
 * Globals.
 *
 ******************************************************************************************/
 
long            gWindowWidth, gWindowHeight;
TQAEngine       *gEngine [kTinselWindows];
TQADrawContext  *gDrawContext [kTinselWindows];
TQATexture      *gTexture [kTinselWindows];
 
/*******************************************************************************************
 *
 * Static variables used by this file's functions only.
 *
 ******************************************************************************************/
 
static float frand (void)
{
    return ((Random() + 32768) / 65536.0);
}
 
/*******************************************************************************************
 *
 * Main. This runs the tests, clearing the windows before each test and waiting for
 * a mouse click after each test. Each test is run four ways: Single and double buffered,
 * with and without 2D clipping.
 *
 ******************************************************************************************/
 
int main()
{
    long        tinselTest, tinselStyle;
    long        i;
    TQAVGouraud vGouraud[3];
    TQAVTexture vTexture[3];
    long        flushCount;
            
    /*
     * If we are running with a shared library, TdLinkEngine should not be defined!
     */
    
    #ifdef dLinkEngine
        (void) TtRegister();
    #endif
    
    /*
     * Create the test window(s).
     */
    
    InitToolbox ();
 
    if ( ! CreateTestWindows (kTinselMaxWindowSize, kTinselMaxWindowSize))
    {
        return (-1);
    }
    if ( ! CreateWindowClip ())
    {
        return (-1);
    }
    if ( ! TestTextureNew())
    {
        return (-1);
    }
    
    /*
     * Run tests.
     */
    
    for (tinselStyle = 0; tinselStyle <= kMaxStyle; ++tinselStyle)
    {
        switch (tinselStyle)
        {
            case kStyleSingleBuffered:
                if ( ! TestDrawContextNew (kQAContext_DeepZ, false))
                {
                    return (-1);
                }
                break;
            
            case kStyleDoubleBuffered:
                if ( ! TestDrawContextNew (kQAContext_DeepZ | kQAContext_DoubleBuffer, false))
                {
                    return (-1);
                }
                break;
                
            case kStyleSingleBufferedClip:
                if ( ! TestDrawContextNew (kQAContext_DeepZ, true))
                {
                    return (-1);
                }
                break;
            
            case kStyleDoubleBufferedClip:
                if ( ! TestDrawContextNew (kQAContext_DeepZ | kQAContext_DoubleBuffer, true))
                {
                    return (-1);
                }
                break;
        }
 
        ClearWindows();
            
        for (tinselTest = 0; tinselTest <= kMaxTest; ++tinselTest)
        {
            switch (tinselTest)
            {
                case kTestPoints:
                    TestRenderStart();
                    for (i = 0, flushCount = kNPoints / kNFlushes; i++ < kNPoints; /* Nothing */)
                    {
                        TestRandomVGouraud (&vGouraud[0]);
                        TestDrawPoint (&vGouraud[0]);
                        if ((i % flushCount) == 0)
                        {
                            TestFlush();
                        }
                    }
                    TestRenderEnd();
                    break;
                    
                case kTestLines:
                    TestRenderStart();
                    for (i = 0, flushCount = kNLines / kNFlushes; i++ < kNLines; /* Nothing */)
                    {
                        TestRandomVGouraud (&vGouraud[0]);
                        TestRandomVGouraud (&vGouraud[1]);
                        TestDrawLine (&vGouraud[0], &vGouraud[1]);
                        if ((i % flushCount) == 0)
                        {
                            TestFlush();
                        }
                    }
                    TestRenderEnd();
                    break;
                    
                case kTestTriGouraud:
                    TestRenderStart();
                    for (i = 0, flushCount = kNTris / kNFlushes; i++ < kNTris; /* Nothing */)
                    {
                        TestRandomVGouraud (&vGouraud[0]);
                        TestRandomVGouraud (&vGouraud[1]);
                        TestRandomVGouraud (&vGouraud[2]);
                        
                        TestDrawTriGouraud (&vGouraud[0],
                                &vGouraud[1], &vGouraud[2], kQATriFlags_None);
                        
                        if ((i % flushCount) == 0)
                        {
                            TestFlush();
                        }
                    }
                    TestRenderEnd();
                    break;
                    
                case kTestTriTexture:
                    TestRenderStart();
                    TestSetStateTexture();
                    for (i = 0, flushCount = kNTris / kNFlushes; i++ < kNTris; /* Nothing */)
                    {
                        /*
                         * Setup the u,v values before calling TestRandomVTexture(),
                         * as it references them.
                         */
                        
                        vTexture[0].uOverW = 0.0;
                        vTexture[0].vOverW = 0.0;
 
                        vTexture[1].uOverW = 0.0;
                        vTexture[1].vOverW = 1.0;
 
                        vTexture[2].uOverW = 1.0;
                        vTexture[2].vOverW = 1.0;
 
                        TestRandomVTexture (&vTexture[0]);
                        TestRandomVTexture (&vTexture[1]);
                        TestRandomVTexture (&vTexture[2]);
                        
                        TestDrawTriTexture (&vTexture[0],
                                &vTexture[1], &vTexture[2], kQATriFlags_None);
                        
                        if ((i % flushCount) == 0)
                        {
                            TestFlush();
                        }
                    }
                    TestRenderEnd();
                    break;
            }
            
            #ifdef dWaitForButton
                /*
                 * Wait for a mouse button click..
                 */
                
                while ( ! Button())
                    /* Do nothing */ ;
                FlushEvents (everyEvent, 0);
            #endif
        }
        
        TestDrawContextDelete();
    }
    
    return (0);
}
 
/*******************************************************************************************
 *
 * Set xyzw fields of a TQAVGouraud randomly. All other fields get simple defaults.
 *
 ******************************************************************************************/
 
void TestRandomVGouraud (
    TQAVGouraud     *v)
{
    v->x = frand() * gWindowWidth;
    v->y = frand() * gWindowHeight;
    v->z = frand();
    v->invW = 1.0 / v->z;
    
    v->a = 1.0;
    v->r = frand();
    v->g = frand();
    v->b = frand();
}
 
/*******************************************************************************************
 *
 * Set xyzw fields of a TQAVTexture randomly. The incoming u,v values are multiplied
 * by the random invW value; all other fields get simple defaults.
 *
 ******************************************************************************************/
 
void TestRandomVTexture (
    TQAVTexture     *v)
{
    v->x = frand() * gWindowWidth;
    v->y = frand() * gWindowHeight;
    v->z = frand();
    v->invW = 1.0 / v->z;
    
    v->uOverW *= v->invW;
    v->vOverW *= v->invW;
    
    v->a = 1.0;
    v->r = 0.0;
    v->g = 0.0;
    v->b = 0.0;
    
    v->kd_r = 1.0;
    v->kd_g = 1.0;
    v->kd_b = 1.0;
    
    v->ks_r = 0.0;
    v->ks_g = 0.0;
    v->ks_b = 0.0;
}
 
/*******************************************************************************************
 *
 * Miscellaneous test functions.
 *
 ******************************************************************************************/
 
void TestRenderStart (void)
{
    long        i;
    
    for (i = 0; i < kTinselWindows; ++i)
    {
        if (gDrawContext [i])
        {
            QARenderStart (gDrawContext [i], NULL, NULL);
        }
    }
}
 
void TestRenderEnd (void)
{
    long        i;
    TQAError    status;
    
    for (i = 0; i < kTinselWindows; ++i)
    {
        if (gDrawContext [i])
        {
            status = QARenderEnd (gDrawContext [i], NULL);
        }
    }
}
 
void TestSetStateTexture (void)
{
    long        i;
    
    for (i = 0; i < kTinselWindows; ++i)
    {
        if (gDrawContext [i])
        {
            QASetPtr (gDrawContext [i], kQATag_Texture, gTexture [i]);
            
            /*
             * NOTE: The current Apple software rasterizer always assumes these
             * kQATextureOp_Modulate | kQATextureOp_Highlight are set, as that's
             * the standard QuickDrawª 3D mode. So if you change this, you may
             * find that the software rasterizer isn't a good test case.
             * (This will be fixed soon...)
             */
            
            QASetInt (gDrawContext [i], kQATag_TextureOp,
                    kQATextureOp_Modulate | kQATextureOp_Highlight);
        }
    }
}
 
void TestFlush (void)
{
    long        i;
    
    for (i = 0; i < kTinselWindows; ++i)
    {
        if (gDrawContext [i])
        {
            QAFlush (gDrawContext [i]);
        }
    }
}
 
void TestDrawPoint (
    const TQAVGouraud   *v)
{
    long        i;
    
    for (i = 0; i < kTinselWindows; ++i)
    {
        if (gDrawContext [i])
        {
            QADrawPoint (gDrawContext [i], v);
        }
    }
}
 
void TestDrawLine (
    const TQAVGouraud   *v0,
    const TQAVGouraud   *v1)
{
    long        i;
    
    for (i = 0; i < kTinselWindows; ++i)
    {
        if (gDrawContext [i])
        {
            QADrawLine (gDrawContext [i], v0, v1);
        }
    }
}
 
void TestDrawTriGouraud (
    const TQAVGouraud   *v0,
    const TQAVGouraud   *v1,
    const TQAVGouraud   *v2,
    unsigned long       flags)
{
    long        i;
    
    for (i = 0; i < kTinselWindows; ++i)
    {
        if (gDrawContext [i])
        {
            QADrawTriGouraud (gDrawContext [i], v0, v1, v2, flags);
        }
    }
}
 
void TestDrawTriTexture (
    const TQAVTexture   *v0,
    const TQAVTexture   *v1,
    const TQAVTexture   *v2,
    unsigned long       flags)
{
    long        i;
    
    for (i = 0; i < kTinselWindows; ++i)
    {
        /*
         * Test both for a draw context, and that a texture was created.
         */
        
        if (gDrawContext [i] && gTexture [i])
        {
            QADrawTriTexture (gDrawContext [i], v0, v1, v2, flags);
        }
    }
}
 
Boolean TestTextureNew (void)
{
    TexturePixel        *pixmap;
    long                x, y;
    long                i;
    
    /*
     * Create the source pixmap. Note that we can't free it (unless we
     * called QATextureDetach()). We just do a procedural map with some
     * checkerboard effect...
     */
    
    if ( ! (pixmap = malloc (sizeof (*pixmap) * kTextureSize * kTextureSize)))
    {
        return (false);
    }
    
    for (x = 0; x < kTextureSize; ++x)
    {
        for (y = 0; y < kTextureSize; ++y)
        {
            pixmap [x + (y << kTextureSizeNBits)].a = 0xff;
            pixmap [x + (y << kTextureSizeNBits)].r = (x & 0x1f) << 3;
            pixmap [x + (y << kTextureSizeNBits)].g = (y & 0x1f) << 3;
            pixmap [x + (y << kTextureSizeNBits)].b = (((x + y) / 2) & 0x1f) << 3;
        }
    }
 
    for (i = 0; i < kTinselWindows; ++i)
    {
        if (gEngine [i])
        {
            /*
             * Create the texture. If this fails, gTexture[i] will be NULL.
             * This is ok, as TestDrawTriTexture() always tests it before calling
             * QADrawTriTexture().
             */
            
            gTexture [i] = CreateMipMapTexture (
                    gEngine [i],                                /* store context */
                    pixmap,                                     /* high res pix map */
                    kTextureSize * sizeof (*pixmap),            /* row bytes */
                    kTextureSizeNBits,                          /* widthNBits */
                    kTextureSizeNBits);                         /* heightNBits */
        }
    }
    
    return (true);
}