home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwdos
/
dostunne.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-15
|
61KB
|
2,474 lines
/**********************************************************************
*
* File : dostunne.c
*
* Abstract : A very simple, sample RenderWare application for
* MS-Dos / PC-Dos. This application has very little
* functionality, but is simply intended as a demonstration
* of how to use the RenderWare API.
*
* This application had been written to be compatible with
* both the fixed and floating-point versions of the
* RenderWare library, i.e., it uses the macros CREAL,
* INT2REAL, RAdd, RDiv, RSub etc. If your application is
* intended for the floating-point version of the library
* only these macros are not necessary.
*
* Please note that this application is intended for
* demonstration purposes only. No support will be
* provided for this code and it comes with no warranty.
*
* This application can be built using the Watcom v9.5 compiler and the
* fixed-point RenderWare v1.3 library as follows:
* wcc386p /I=\rw\include /zW /4r /zp4 /mf /fpc /s /j /ei /oxtail
* /DRWFIXED /fo=dostunne.obj dostunne.c
* wlink option caseexact option stack=32768 name dostunne
* file dostunne.obj,\rw\lib\rwdrxp.lib
*
* This application can be built using the Watcom v9.5 compiler and the
* floating-point RenderWare v1.3 library as follows:
* wcc386p /I=\rw\include /zW /4r /zp4 /mf /7 /s /j /ei /oxtailm
* /DRWFLOAT /fo=dostunne.obj dostunne.c
* wlink option caseexact option stack=32768 name dostunne
* file dostunne.obj,\rw\lib\rwdrlp.lib
*
* This file is a product of Criterion Software Ltd.
*
* This file is provided as is with no warranties of any kind and is
* provided without any obligation on Criterion Software Ltd. or
* Canon Inc. to assist in its use or modification.
*
* Criterion Software Ltd. and Canon Inc. will not, under any
* circumstances, be liable for any lost revenue or other damages arising
* from the use of this file.
*
* Copyright (c) 1991, 1992, 1993. Canon Inc.
* All Rights Reserved.
*
**********************************************************************/
/****************************************************************************
Includes
*/
#include <i86.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h> /* Required for floating point */
#include <string.h>
#include "rwlib.h"
#include "rwdos.h"
#include "doswrap.h"
/****************************************************************************
Types
*/
/**********************************************************************
*
* Application constants.
*
**********************************************************************/
#define FIRE_FRAMES 4
#define HOLE_RADIUS 15
#define MAX_TEXTURES 20
#define MAX_RINGS 20
#define FORESHORT_RING 10
#define MAX_OBJECTS 10
#define MAX_EXPLOSION 40
#define EXPLOSION_VEL CREAL(0.02)
#define EXPLOSION_BITS 15
#define FORCE_OF_GRAVITY 0.002
#define BIT_REDUCE CREAL(0.003)
#define BIT_MINIMUM CREAL(0.002)
/*
* Ring Types
*/
#define RING_COLOR 0
#define RING_ROTATE 1
#define TYPE_BIT 1
#define TYPE_OBJECT 2
#define SIZE_OBJECT CREAL(0.5)
#define SIZE_BIT CREAL(0.1)
#define OBJECT_ACCEL CREAL(0.01)
/*
* And the rest
*/
#define DELETE 8
#define BOOL int
/*
* MS Windows compatible defines
*/
#define MK_CONTROL 0x4
#define MK_SHIFT 0x2
/*
* Depending which video mode is being used the colur used will change
*/
/*
* Default distance of the camera from the origin.
*/
#define DEFAULT_CAMERA_DISTANCE CREAL(-7.0)
/* PI !*/
#define PI 3.141592654
/**********************************************************************
*
* Type definitions.
*
**********************************************************************/
typedef struct {
RwTexture *taTextures[MAX_TEXTURES];
int nAmoTextures;
int nCount;
int nDisp;
int nTexWidth;
int nTexHeight;
int nX;
int nY;
int nTexture;
} Textures;
typedef struct {
int nWidth;
int nDepth;
RwPolygon3d ***ppaPoly;
RwPolygon3d **paPolyData;
RwReal nSegLength;
RwReal nSize;
RwReal nOffAngle;
RwClump *cpTube;
RwMatrix4d *mpTubeRot;
RwMatrix4d *mpTubeFlip;
RwMatrix4d *mpTubePos;
RwV3d vTubePos;
RwReal nStepSize;
int nSteps;
int nCurStep;
RwReal nStepPos;
Textures DispTextures;
} Tube;
typedef struct {
int nType;
RwRGBColor cColA;
RwRGBColor cColB;
int nParam1;
int nParam2;
int nParam3;
} RingData;
typedef struct {
RingData raRings[MAX_RINGS];
} Ring;
typedef struct ObjectTag
{
int nType;
RwClump *cpGeo;
RwV3d vPos,vVel;
RwMatrix4d *mpRot,*mpPos;
int nParam1;
RwReal nParam2;
} Object;
/****************************************************************************
Stack Class
*/
typedef struct StackTag {
int nElementSize;
char *pData;
char *pCurPtr;
int nAmoElements;
int nCurElement;
} Stack;
/****************************************************************************
And the rest
*/
typedef struct AllObjectsTag {
Stack sDisplay;
Stack sExplosion;
Stack sObjects;
int nOrthoCount;
} AllObjects;
typedef struct LaunchTag {
int nTime;
int nCurSpeed;
int nSpeed;
} Launch;
/**********************************************************************
*
* Application global variables.
*
**********************************************************************/
/*
*
*/
static AllObjects aoGObjects;
static Tube tGTube;
static Ring rGRing;
static Launch lGLaunch;
RwRGBColor caGColors[]={{CREAL(1.0),CREAL(0.0),CREAL(0.0)},
{CREAL(0.0),CREAL(1.0),CREAL(0.0)},
{CREAL(0.0),CREAL(0.0),CREAL(1.0)},
{CREAL(0.5),CREAL(1.0),CREAL(0.0)},
{CREAL(0.0),CREAL(0.5),CREAL(0.5)},
{CREAL(0.0),CREAL(1.0),CREAL(1.0)},
{CREAL(0.5),CREAL(1.0),CREAL(0.0)},
{CREAL(1.0),CREAL(0.5),CREAL(0.1)} };
int nGColorMask=7;
/*
* Texts colour
*/
static int nGTextColour;
/*
* Global RenderWare object pointers. In this simple application we
* make use of only a single scene, camera and light.
*/
static RwScene *Scene = NULL;
static RwCamera *Camera = NULL;
static RwLight *Light = NULL;
/*
* Current distance the camera is from the origin. This is stored to
* help us pan and zoom the camera.
*/
static RwReal CameraDistance = DEFAULT_CAMERA_DISTANCE;
/*
* Current animation frame number. This is incremented each time a
* frame is drawn on timer expiry. The purpose of this variable is
* to enable us to periodically (based on the number of frames) call
* RwOrthoNormalizeMatrix() to correct any errors which have crept
* into the clump's joint matrix because of the inevitable
* restrictions on the accuracy of fixed-point numbers. See
* HandleTimer for more details.
*/
static int nGFrameNumber = 0;
/*
* This flag indicates whether the 3D components of the application
* have been successfully initialized as yet. It is used to guard
* the message loop handler functions from being invoked before the
* 3D components of the application are successfully initialized.
*/
static BOOL ThreeDInitialized = FALSE;
/*
* The size of the screen
*/
static int nGScrWidth;
static int nGScrHeight;
/****************************************************************************
Cursor Images
*/
/* 16 by 16 image */
#define MOUSE_ARROW_X 0
#define MOUSE_ARROW_Y 0
#define MOUSE_ARROW_W 16
#define MOUSE_ARROW_H 16
static void *pGMouseArrow;
static char sGMouseArrow[]="\
aaaa \
abbbaaa \
abbbbbbaaa \
abbbbbbbbba \
abbbbbbba \
abbbbbba \
abbbbbba \
abbbbbba \
abbaabbba \
aba abbba \
a abbba \
abbba \
abbba \
abba \
aa \
";
/* 13 x 13 */
#define MOUSE_FIRE_X 6
#define MOUSE_FIRE_Y 6
#define MOUSE_FIRE_W 13
#define MOUSE_FIRE_H 13
static void *pGMouseFire;
static char sGMouseFire[]="\
a \
aba \
aba \
aba \
aba \
aaaaabaaaaa \
abbbbbbbbbbba\
aaaaabaaaaa \
aba \
aba \
aba \
aba \
a \
";
/* 11 x 10 */
#define MOUSE_SIGHT_X 6
#define MOUSE_SIGHT_Y 5
#define MOUSE_SIGHT_W 11
#define MOUSE_SIGHT_H 10
static void *pGMouseSight;
static char sGMouseSight[]="\
aaaaaaa \
abbbbbbba \
ab ba\
ab ba\
ab ba\
ab ba\
ab ba\
ab ba\
abbbbbbba \
aaaaaaa ";
/* Pick info */
static RwPickRecord pGPick;
static int nGPickStatus;
/* Fire Counter */
static int nGFireCount;
/****************************************************************************
Proto types
*/
/* Stack Prototypes */
int StackCreate(Stack *spStack,int nEleSize,int nAmoEle);
void *StackData(Stack *spStack);
int StackElements(Stack *spStack);
int StackDestroy(Stack *spStack);
void *StackPush(Stack *spStack,void *pData);
int StackPop(Stack *spStack,void *pData);
void StackForAll(Stack *spStack,void (*Func)(void *pData,void *pUser),
void *pUser);
int StackRemove(Stack *spStack,void *pEle);
/* AllObjects */
void AllObjectsRemove(AllObjects *aopObj,Stack *spObj,Object *opObj);
Object *AllObjectsAdd(AllObjects *aoObj,Stack *spObj);
/****************************************************************************
LaunchCreate
On entry : Launch Structure
: Speed of launch
On exit :
*/
void LaunchCreate(Launch *lpLaunch,int nSpeed)
{
lpLaunch->nSpeed = nSpeed;
lpLaunch->nCurSpeed = nSpeed;
lpLaunch->nTime = nSpeed;
}
/****************************************************************************
StackCreate
On entry : Pointer to stack structure
On exit : 0 if all went to plan
*/
int StackCreate(Stack *spStack,int nEleSize,int nAmoEle)
{
if (!(spStack->pData = (char *) malloc (nEleSize*nAmoEle))) {
return 1;
};
spStack->nCurElement = 0;
spStack->pCurPtr = spStack->pData;
spStack->nAmoElements = nAmoEle;
spStack->nElementSize = nEleSize;
return 0;
}
/****************************************************************************
StackData
On entry : Stack
On exit : Stacks contents as an array bottom element first
*/
void *StackData(Stack *spStack)
{
return spStack->pData;
}
/****************************************************************************
StackElements
On entry : Stack
On exit : Amount of entries in the stack
*/
int StackElements(Stack *spStack)
{
return spStack->nCurElement;
}
/****************************************************************************
StackFront
On entry : Stack
: Element too stick on the bottom of the stack
On exit : Pointer to entry on stack,NULL for fail
*/
void *StackFront(Stack *spStack,void *pData)
{
char *pTmp;
int nCount;
if (spStack->nCurElement==spStack->nAmoElements) {
return NULL;
} else {
pTmp = spStack->pCurPtr;
for (nCount=0;nCount<spStack->nCurElement;nCount++) {
memcpy(pTmp,pTmp-spStack->nElementSize,spStack->nElementSize);
pTmp -= spStack->nElementSize;
};
memcpy(spStack->pData,pData,spStack->nElementSize);
spStack->pCurPtr+=spStack->nElementSize;
spStack->nCurElement++;
return spStack->pData;
};
}
/****************************************************************************
StackDestroy
On entry : Stack
On exit : 0 if all went to plan
*/
int StackDestroy(Stack *spStack)
{
free(spStack->pData);
return 0;
}
/****************************************************************************
StackPush
On entry : Stack
: Pointer to element to push
On exit : Pointer to Saved object if all ok else NULL
*/
void *StackPush(Stack *spStack,void *pData)
{
void *pSave;
if (spStack->nCurElement==spStack->nAmoElements) {
return NULL;
} else {
pSave = spStack->pCurPtr;
memcpy(pSave,pData,spStack->nElementSize);
spStack->pCurPtr+=spStack->nElementSize;
spStack->nCurElement++;
return pSave;
};
}
/****************************************************************************
StackPop
On entry : Stack
On exit : 0 if all ok
*/
int StackPop(Stack *spStack,void *pData)
{
if (!spStack->nCurElement) {
return 1;
} else {
spStack->nCurElement--;
spStack->pCurPtr-=spStack->nElementSize;
memcpy(pData,spStack->pCurPtr,spStack->nElementSize);
return 0;
};
}
/****************************************************************************
StackForAll
Goes from top of stack to bottom
On entry : Stack
: Function to be called
: Pointer to user data
*/
void StackForAll(Stack *spStack,void (*Func)(void *pData,void *pUser),
void *pUser)
{
char *pData;
int nCount;
pData = spStack->pCurPtr-spStack->nElementSize;
for (nCount=spStack->nCurElement;nCount--;nCount) {
(*Func)(pData,pUser);
pData-=spStack->nElementSize;
};
}
/****************************************************************************
StackRemove
Removes an entry from the stack
On entry : Stack
: Element to remove
On exit : 0 if all ok
*/
int StackRemove(Stack *spStack,void *pEle)
{
char *pData=(char *)pEle;
while (pData!=(spStack->pCurPtr-spStack->nElementSize)) {
memcpy(pData,pData+spStack->nElementSize,spStack->nElementSize);
pData+=spStack->nElementSize;
};
spStack->pCurPtr-=spStack->nElementSize;
spStack->nCurElement--;
return 0;
}
/****************************************************************************
CreateExplosion
On entry : Vector position of explosion
: Amount of Bits
On exit :
*/
void CreateExplosion(AllObjects *aopObj,RwV3d *vpPos,RwV3d *vpVel,int nAmo)
{
Object *opObj;
RwReal nRand;
RwPushScratchMatrix();
while (((opObj = AllObjectsAdd(aopObj,&aopObj->sExplosion))!=NULL)
&&(nAmo-->0)) {
opObj->vPos = (*vpPos);
opObj->vVel = (*vpVel);
nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
opObj->vVel.x += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
EXPLOSION_VEL);
nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
opObj->vVel.y += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
EXPLOSION_VEL);
nRand = RDiv(INT2REAL(rand()>>1),CREAL(16384.0));
opObj->vVel.z += RSub(RMul(RAdd(EXPLOSION_VEL,EXPLOSION_VEL),nRand),
EXPLOSION_VEL);
opObj->nParam1=14+((nRand>>2)&15);
RwCopyMatrix(opObj->mpPos, RwScratchMatrix());
RwTranslateMatrix(RwScratchMatrix(), opObj->vPos.x,
opObj->vPos.y,
opObj->vPos.z, rwPOSTCONCAT);
RwTransformClump(opObj->cpGeo, RwScratchMatrix(), rwREPLACE);
opObj->nParam2 = SIZE_BIT;
RwScaleMatrix(RwScratchMatrix(),opObj->nParam2,
opObj->nParam2,
opObj->nParam2,
rwREPLACE);
RwTransformClumpJoint(opObj->cpGeo,RwScratchMatrix(),rwREPLACE);
};
RwPopScratchMatrix();
}
/*****************************************************************************
AllObjectsCreate
On entry : AllObjects
On exit : 0 if all ok
*/
int AllObjectsCreate(AllObjects *aopObj)
{
int nStatus;
nStatus = StackCreate(&aopObj->sDisplay,sizeof(Object),MAX_EXPLOSION+MAX_OBJECTS);
nStatus |= StackCreate(&aopObj->sExplosion,sizeof(Object),MAX_EXPLOSION);
nStatus |= StackCreate(&aopObj->sObjects,sizeof(Object),MAX_OBJECTS);
return nStatus;
}
/*************************************************************************
MakeZippy - Sets polygon to a random colour
(called from RwForAllPolygonsInClump)
On entry : Polygon
On exit :
*/
static void MakeZippy(RwPolygon3d *p)
{
static int zippy = 0;
switch (zippy % 7)
{
case 0: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.0), CREAL(0.0)); break;
case 1: RwSetPolygonColor(p, CREAL(0.8), CREAL(0.1), CREAL(0.2)); break;
case 2: RwSetPolygonColor(p, CREAL(0.9), CREAL(0.6), CREAL(0.3)); break;
case 3: RwSetPolygonColor(p, CREAL(0.9), CREAL(0.0), CREAL(0.2)); break;
case 4: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.0)); break;
case 5: RwSetPolygonColor(p, CREAL(0.6), CREAL(0.5), CREAL(0.0)); break;
case 6: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.2)); break;
}
zippy++;
}
/*************************************************************************
MakeColour - Sets polygon to a random colour
(called from RwForAllPolygonsInClump)
On entry : Polygon
On exit :
*/
static void MakeColour(RwPolygon3d *p)
{
static int zippy = 0;
switch (zippy % 7)
{
case 0: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.0), CREAL(0.0)); break;
case 1: RwSetPolygonColor(p, CREAL(0.0), CREAL(0.7), CREAL(0.0)); break;
case 2: RwSetPolygonColor(p, CREAL(0.0), CREAL(0.0), CREAL(0.7)); break;
case 3: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.0)); break;
case 4: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.0), CREAL(0.7)); break;
case 5: RwSetPolygonColor(p, CREAL(0.0), CREAL(0.7), CREAL(0.7)); break;
case 6: RwSetPolygonColor(p, CREAL(0.7), CREAL(0.7), CREAL(0.7)); break;
}
zippy++;
}
/***************************************************************************
RandomVec - create a random vector
On entry : Random vector to create
On exit :
*/
static void RandomVec(RwV3d *vec)
{
vec->x = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
vec->y = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
vec->z = RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0));
}
/****************************************************************************
StackExplosionCreate
On entry : Stack To set up with explosions
On exit : 0 if all ok
*/
int StackExplosionCreate(Stack *spExp)
{
int nCount;
RwClump *cpBit;
RwClump *cpGeo;
RwV3d vTmp;
Object oBit;
/* Create the clump which is an explosion bit */
RwModelBegin();
RwClumpBegin();
RwSetSurface(CREAL(0.4), CREAL(0.7), CREAL(0.0));
RwSetSurfaceColor(CREAL(1.0),CREAL(1.0),CREAL(1.0));
RwSetHints(0);
RwVertex(CREAL(0.866),CREAL(0.5),CREAL(0));
RwVertex(CREAL(-0.866),CREAL(0.5),CREAL(0));
RwVertex(CREAL(0),CREAL(1.0),CREAL(0));
RwTriangle(1,2,3);
RwTriangle(3,2,1);
RwClumpEnd(&cpBit);
RwModelEnd();
/* For all explosion bits */
for (nCount=0;nCount<MAX_EXPLOSION;nCount++) {
/* Make a copy of the bit clump */
cpGeo = RwDuplicateClump(cpBit);
/* Zippify the bit */
RwForAllPolygonsInClump(cpGeo, MakeZippy);
/* Mark as bit and unused */
RwSetClumpData(cpGeo,NULL); /* Mark with Null pointer */
oBit.nType = TYPE_BIT;
oBit.cpGeo = cpGeo;
RwIdentityMatrix(oBit.mpRot = RwCreateMatrix());
RwIdentityMatrix(oBit.mpPos = RwCreateMatrix());
/* Give it a random rotation */
RandomVec(&vTmp);
RwRotateMatrix(oBit.mpRot,vTmp.x,vTmp.y,vTmp.z,
RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(15.0)),
rwREPLACE);
RwPushScratchMatrix();
RwScaleMatrix(RwScratchMatrix(),SIZE_BIT,SIZE_BIT,SIZE_BIT,rwREPLACE);
RwTransformClumpJoint(oBit.cpGeo,RwScratchMatrix(),rwREPLACE);
RwPopScratchMatrix();
StackPush(spExp,&oBit);
};
/* Destroy the default clump */
RwDestroyClump(cpBit);
return 0;
}
/****************************************************************************
StackObjectsCreate
On entry : Stack
On exit : 0 if all went to plan
*/
int StackObjectsCreate(Stack *spObj,int nGeo)
{
RwClump *cpDefault,*cpLoad;
RwV3d vTmp;
int nCount;
char saFiles[][14]={"z.rwx",
"ball.rwx",
"c.rwx",
"table.rwx",
"slab.rwx",
"torus.rwx",
"banana.rwx",
"lampshad.rwx",
"dummy.rwx"};
int nFiles=8;
Object oObj;
Object *opObj;
if (nGeo) {
RwModelBegin();
RwClumpBegin();
RwSetSurface(CREAL(0.4), CREAL(0.7), CREAL(0.0));
RwSetSurfaceColor(RDiv(CREAL(1.0), INT2REAL(1 + (rand() % 4))),
RDiv(CREAL(1.0), INT2REAL(1 + (rand() % 4))),
RDiv(CREAL(1.0), INT2REAL(1 + (rand() % 4))));
RwSphere(CREAL(0.1),3);
RwClumpEnd(&cpDefault);
RwModelEnd();
for (nCount=0;nCount<nFiles;nCount++) {
oObj.nType = TYPE_OBJECT;
oObj.vVel.x = CREAL(0.0);
oObj.vVel.y = CREAL(0.0);
oObj.vVel.z = CREAL(0.0);
RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
RandomVec(&vTmp);
RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
rwREPLACE);
cpLoad = RwReadShape(saFiles[nCount]);
if (!cpLoad) {
cpLoad = RwDuplicateClump(cpDefault);
};
RwPushScratchMatrix();
RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
RwPopScratchMatrix();
oObj.cpGeo = cpLoad;
opObj = (Object *)StackPush(spObj,&oObj);
};
RwDestroyClump(cpDefault);
} else {
/* geometry */
oObj.nType = TYPE_OBJECT;
oObj.vVel.x = CREAL(0.0);
oObj.vVel.y = CREAL(0.0);
oObj.vVel.z = CREAL(0.0);
RwModelBegin();
RwSetSurfaceColor(CREAL(1.0),CREAL(0.5),CREAL(0.0));
RwSetSurface(CREAL(0.3),CREAL(0.4),CREAL(0.1));
RwSetSurfaceLightSampling(rwFACET);
RwSetSurfaceGeometrySampling(rwSOLID);
/* ! */
RwClumpBegin();
RwSphere(CREAL(1.0),3);
RwClumpEnd(&cpLoad);
RwForAllPolygonsInClump(cpLoad, MakeColour);
RwPushScratchMatrix();
RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
RwPopScratchMatrix();
RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
RandomVec(&vTmp);
RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
rwREPLACE);
oObj.cpGeo = cpLoad;
StackPush(spObj,&oObj);
/* ! */
RwClumpBegin();
RwTranslateCTM(CREAL(0.0), CREAL(-0.15/2), CREAL(0.0));
RwCone(CREAL(0.15), CREAL(0.1), 12);
RwRotateCTM(CREAL(1.0), CREAL(0.0), CREAL(0.0), CREAL(180.0));
RwDisc(CREAL(0.0), CREAL(0.1), 12);
RwClumpEnd(&cpLoad);
RwForAllPolygonsInClump(cpLoad, MakeColour);
RwPushScratchMatrix();
RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
RwPopScratchMatrix();
RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
RandomVec(&vTmp);
RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
rwREPLACE);
oObj.cpGeo = cpLoad;
StackPush(spObj,&oObj);
/* !*/
RwClumpBegin();
RwBlock(CREAL(0.1), CREAL(0.4), CREAL(0.9));
RwClumpEnd(&cpLoad);
RwForAllPolygonsInClump(cpLoad, MakeColour);
RwPushScratchMatrix();
RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
RwPopScratchMatrix();
RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
RandomVec(&vTmp);
RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
rwREPLACE);
oObj.cpGeo = cpLoad;
StackPush(spObj,&oObj);
/* !*/
RwClumpBegin();
RwTranslateCTM(CREAL(0.0), CREAL(-0.15/2), CREAL(0.0));
RwCylinder(CREAL(0.15), CREAL(0.1), CREAL(0.1), 12);
RwDisc(CREAL(0.15), CREAL(0.1), 12);
RwRotateCTM(CREAL(1.0), CREAL(0.0), CREAL(0.0), CREAL(180.0));
RwDisc(CREAL(0.0), CREAL(0.1), 12);
RwClumpEnd(&cpLoad);
RwForAllPolygonsInClump(cpLoad, MakeColour);
RwPushScratchMatrix();
RwScaleMatrix(RwScratchMatrix(),SIZE_OBJECT,SIZE_OBJECT,SIZE_OBJECT,rwREPLACE);
RwTransformClumpJoint(cpLoad,RwScratchMatrix(),rwREPLACE);
RwPopScratchMatrix();
RwIdentityMatrix(oObj.mpRot = RwCreateMatrix());
RwIdentityMatrix(oObj.mpPos = RwCreateMatrix());
RandomVec(&vTmp);
RwRotateMatrix(oObj.mpRot,vTmp.x,vTmp.y,vTmp.z,
RMul(RSub(RDiv(INT2REAL(rand()),CREAL(16384.0)), CREAL(1.0)),CREAL(10.0)),
rwREPLACE);
oObj.cpGeo = cpLoad;
StackPush(spObj,&oObj);
RwModelEnd();
};
return 0;
}
/****************************************************************************
AllObjectsFixPtrs
On entry : All Objects
On exit :
*/
void _AllObjectsFixPtrs(void *pData,void *pUser)
{
Object *opObj=(Object *)pData;
/* Stop warnings */
pUser=pUser;
switch (opObj->nType) {
case TYPE_BIT: {
RwSetClumpData(opObj->cpGeo,NULL);
break;
};
case TYPE_OBJECT: {
RwSetClumpData(opObj->cpGeo,opObj);
break;
};
};
}
void AllObjectsFixPtrs(AllObjects *aopObj)
{
StackForAll(&aopObj->sDisplay,_AllObjectsFixPtrs,aopObj);
}
/****************************************************************************
AllObjectsUpdate
On entry : All Objects
On exit :
*/
void _AllObjectsUpdate(void *pData,void *pUser)
{
Object *opObj=(Object *)pData;
AllObjects *aopObj = (AllObjects *)pUser;
aopObj->nOrthoCount++;
switch (opObj->nType) {
case TYPE_BIT: {
RwMultiplyMatrix(opObj->mpPos,opObj->mpRot,RwScratchMatrix());
if (!(nGFrameNumber+aopObj->nOrthoCount)&127) {
RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
};
RwCopyMatrix(RwScratchMatrix(), opObj->mpPos);
RwAddVector(&opObj->vPos,&opObj->vVel,&opObj->vPos);
opObj->vVel.y -= CREAL(FORCE_OF_GRAVITY);
RwTranslateMatrix(RwScratchMatrix(), opObj->vPos.x,
opObj->vPos.y,
opObj->vPos.z, rwPOSTCONCAT);
RwTransformClump(opObj->cpGeo, RwScratchMatrix(), rwREPLACE);
opObj->nParam2-=BIT_REDUCE;
if (opObj->nParam2<BIT_MINIMUM) {
opObj->nParam2 = BIT_MINIMUM;
};
RwScaleMatrix(RwScratchMatrix(),opObj->nParam2,
opObj->nParam2,
opObj->nParam2,
rwREPLACE);
RwTransformClumpJoint(opObj->cpGeo,RwScratchMatrix(),rwREPLACE);
if (!(opObj->nParam1--)) {
AllObjectsRemove(aopObj,&aopObj->sExplosion,opObj);
};
break;
};
case TYPE_OBJECT: {
RwMultiplyMatrix(opObj->mpPos,opObj->mpRot,RwScratchMatrix());
if (!(nGFrameNumber+aopObj->nOrthoCount)&127) {
RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
};
RwCopyMatrix(RwScratchMatrix(), opObj->mpPos);
RwTranslateMatrix(RwScratchMatrix(), opObj->vPos.x,
opObj->vPos.y,
opObj->vPos.z, rwPOSTCONCAT);
RwTransformClump(opObj->cpGeo, RwScratchMatrix(), rwREPLACE);
opObj->vVel.x -= RMul(opObj->vPos.x,OBJECT_ACCEL);
opObj->vVel.y -= RMul(opObj->vPos.y,OBJECT_ACCEL);
opObj->vPos.x += opObj->vVel.x;
opObj->vPos.y += opObj->vVel.y;
if (opObj->vPos.z>(-DEFAULT_CAMERA_DISTANCE-RDiv(SIZE_OBJECT,CREAL(2))) ) {
AllObjectsRemove(aopObj,&aopObj->sObjects,opObj);
};
break;
};
};
opObj->vPos.z+= tGTube.nStepSize;
}
void AllObjectsUpdate(AllObjects *aopObj)
{
/* Do the display Update */
aopObj->nOrthoCount=0;
RwPushScratchMatrix();
StackForAll(&aopObj->sDisplay,_AllObjectsUpdate,aopObj);
RwPopScratchMatrix();
}
/****************************************************************************
AllObjectsAdd
On entry : All Objects
: Stack to add from
On exit : Pointer to object (NULL if not found)
*/
Object *AllObjectsAdd(AllObjects *aoObj,Stack *spObj)
{
Object oObj;
Object *pObj;
if (!StackPop(spObj,&oObj)) {
pObj = StackPush(&aoObj->sDisplay,&oObj);
RwAddClumpToScene(Scene,oObj.cpGeo);
if (pObj->nType==TYPE_OBJECT) {
RwSetClumpData(oObj.cpGeo,(void *)pObj); /* Mark with data pointer */
} else {
RwSetClumpData(oObj.cpGeo,NULL);
};
AllObjectsFixPtrs(aoObj);
return pObj;
};
return (Object *)NULL;
}
/****************************************************************************
AllObjectsRemove
On entry : All objects
: Object to remove
*/
void AllObjectsRemove(AllObjects *aopObj,Stack *spObj,Object *opObj)
{
RwRemoveClumpFromScene(opObj->cpGeo);
RwSetClumpData(opObj->cpGeo,NULL);
switch (opObj->nType) {
case TYPE_BIT: {
StackPush(spObj,opObj);
break;
};
case TYPE_OBJECT: {
StackFront(spObj,opObj);
break;
};
default: {
break;
};
};
StackRemove(&aopObj->sDisplay,opObj);
AllObjectsFixPtrs(aopObj);
}
/****************************************************************************
EnemyLaunchHandler
On entry : AllObjects
On exit :
*/
void EnemyLaunchHandler(Launch *lpLau,AllObjects *aopObj)
{
Object *opObj;
if (!lpLau->nTime) {
opObj = AllObjectsAdd(aopObj,&aopObj->sObjects);
if (opObj) {
opObj->vPos.x = RDiv(INT2REAL((rand()&511)-256),CREAL(512));
opObj->vPos.y = RDiv(INT2REAL((rand()&511)-256),CREAL(512));
opObj->vPos.z = DEFAULT_CAMERA_DISTANCE;
opObj->vVel.x = CREAL(0.0);
opObj->vVel.y = CREAL(0.0);
opObj->vVel.z = CREAL(0.0);
};
lpLau->nTime=lpLau->nSpeed;
} else {
lpLau->nTime--;
};
}
/****************************************************************************
DosPrintString
On entry : xcord
: ycord
: string
: colour
On exit :
*/
void DosPrintString(int nX,int nY,char *sString,int nCol)
{
RwPrintChar pcPrint;
pcPrint.x = nX;
pcPrint.y = nY;
pcPrint.color = nCol;
for (;(*sString);sString++) {
pcPrint.c = (*sString);
RwDeviceControl(rwPRINTCHAR,0,&pcPrint,sizeof(pcPrint));
pcPrint.x+=8;
};
}
/****************************************************************************
DosGetKey
Get the ascii key code of any depressed key. (Do not wait for a key press.
-> return 0 if no key is pressed)
On entry :
On exit : Key pressed in ascii (or 0 if no key pressed)
*/
int DosGetKey(void)
{
union REGPACK rp;
memset(&rp,0,sizeof(rp));
rp.h.ah = 0x06;
rp.h.dl = 0xff;
intr(0x21,&rp);
if (!(rp.w.flags & 0x40 )) { /* Check Z flag */
/* Got key */
if (rp.h.al) {
return ((int)rp.h.al);
};
memset(&rp,0,sizeof(rp));
rp.h.ah = 0x06;
rp.h.dl = 0xff;
intr(0x21,&rp);
if (!(rp.w.flags & 0x40)) {
return ((int)rp.h.al);
};
return (rp.h.al|0x80);
};
return 0;
}
/**********************************************************************/
/*
* This function initializes the 3D (i.e. RenderWare) components of the
* application. This function opens the RenderWare library, creates a
* camera, a scene, a light and a matrix for spinning. A user-draw may
* also be created if USERDRAW_LABELS is defined.
*/
static BOOL
Init3D(char *sFilename)
{
char windowText[128];
char version[30];
char buffer[128];
int param;
int i;
RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
long nError;
/*
* Attempt to open (and initialize) the RenderWare library.
*/
if (!RwOpen("DOSMOUSE", &nError))
{
printf("Unable to access renderware!!\n");
switch (nError) {
case E_RW_DOS_MODE_UNAVAILABLE: {
printf("The installed VESA card is unable to switch to the resolution");
printf(" requested.\n");
printf("Either install a different video adapter or use a ");
printf("supported video mode.");
break;
};
case E_RW_DOS_NO_VESA_BIOS: {
printf("A VESA bios is unavailable on this machine.\n");
printf("Either use a VESA compatible Video Adapter or install a ");
printf("VESA bios emulation TSR.\n");
break;
};
case E_RW_DOS_INCOMPATIBLE_BIOS: {
printf("The VESA bios on this machine is not of high enough version ");
printf("to function\ncorrectly with RenderWare. Use a version 1.0 or");
printf(" higher VESA bios or TSR.\n");
break;
};
case E_RW_DOS_NO_MOUSE: {
printf("No Microsoft compatible mouse driver present.\n");
printf("Install a microsoft compatible mouse driver and try again.\n");
break;
};
default: {
printf("Unknown Error !!!!!!!!!!!!!!!\n");
break;
};
};
return FALSE;
}
/* Set up character set */
RwGetDeviceInfo(rwSCRHEIGHT,&nGScrHeight,sizeof(nGScrHeight));
RwGetDeviceInfo(rwSCRWIDTH,&nGScrWidth,sizeof(nGScrWidth));
nGTextColour = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
/*--- Only look for scripts and textures in subdirectories under the current
one. RWSHAPEPATH need not be set then */
RwSetShapePath(".",rwPRECONCAT);
strcpy(buffer,sFilename);
i = strlen(buffer);
while((buffer[i] != '\\')&&(i>=0)) {
i--;
};
if (i>=0) {
buffer[i+1] = 0;
strcat(buffer, "TEXTURES");
RwSetShapePath(buffer, rwPOSTCONCAT);
buffer[i+1] = 0;
strcat(buffer, "SCRIPTS");
RwSetShapePath(buffer, rwPOSTCONCAT);
};
RwSetShapePath("SCRIPTS", rwPRECONCAT);
RwSetShapePath("TEXTURES", rwPRECONCAT);
/*
* Label the display with information about the version of
* RenderWare being used. Its rather unlikely that
* RwGetSystemInfo() will fail so we ignore its return value.
*/
RwGetSystemInfo(rwVERSIONSTRING, &version,sizeof(version));
RwGetSystemInfo(rwFIXEDPOINTLIB, ¶m,sizeof(param));
sprintf(windowText, "DosTunnel V%s %s",
version, (param ? "Fixed" : "Float"));
DosPrintString(0,nGScrHeight-16,windowText,nGTextColour);
/*
* Create the camera which will be used for rendering.
*/
Camera = RwCreateCamera(nGScrWidth,nGScrHeight-24, NULL);
if (!Camera)
{
/*
* As with RwOpen(), the most common cause for a failure to create
* a camera is insufficient memory so we will explicitly check for
* this condition and report it. Otherwise a general error is issued.
*/
if (RwGetError() == E_RW_NOMEM)
{
RwClose();
printf("Insufficient memory to create the RenderWare(tm) camera\n");
}
else
{
RwClose();
printf("Error creating the RenderWare(tm) camera\n");
}
exit(-1);
}
RwSetCameraViewport(Camera, 0, 0, nGScrWidth, nGScrHeight-24);
/*
* Set the camera's background color to blue.
*/
RwSetCameraBackColor(Camera, CREAL(0.0), CREAL(0.0), CREAL(0.3));
/*
* By default, the camera lies on the X-Z plane and points down Z
* into the screen. We shall retain the camera's orientation, but move
* the camera DEFAULT_CAMERA_DISTANCE units down Z away from the screen.
*/
RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CameraDistance);
/*
* Another change from previous versions of RenderWare is the amount of
* prespective generated by the default viewwindow size. When converting
* applications from previous versions of RenderWare the simple rule is
* to divide the viewwindow size by five to get the same prespective effect
* as given under previous versions.
*/
if (nGScrWidth >= nGScrHeight) {
RwSetCameraViewwindow(Camera,
CREAL(1.0),
RMul(CREAL(1.0),
RDiv(INT2REAL(nGScrHeight),
INT2REAL(nGScrWidth))));
} else {
RwSetCameraViewwindow(Camera,
RMul(CREAL(1.0),
RDiv(INT2REAL(nGScrWidth),
INT2REAL(nGScrHeight))),
CREAL(1.0));
};
/*
* Create a scene which will contain the clumps to be rendered and the
* light or lights illuminating those clumps . In this very simple
* application it would be perfectly acceptable to use the default scene
* (as returned by RwDefaultScene()) for rendering. However, it is good
* practice to always create a scene which will be used for your rendering
* and only use the default scene as a bag for currently unused clumps and
* lights.
*/
Scene = RwCreateScene();
if (!Scene)
{
RwDestroyCamera(Camera);
RwClose();
printf("Error creating the RenderWare(tm) scene\n");
exit(-1);
}
/*
* Our scene will be illuminated by a directional light. The illumination
* vector of the light is (-1.0, -1.0, -1.0) and its brightness will be 1.0.
*/
Light = RwCreateLight(rwDIRECTIONAL, CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
CREAL(1.0));
if (!Light)
{
RwDestroyScene(Scene);
RwDestroyCamera(Camera);
RwClose();
printf("Error creating the RenderWare(tm) light\n");
exit(-1);
}
/*
* Add the new light to our scene.
*/
RwAddLightToScene(Scene, Light);
/*
* All the 3D components are now successfully initialized, so
* work can begin...
*/
ThreeDInitialized = TRUE;
return TRUE;
}
/**********************************************************************/
/*
* This function shuts down the 3D (i.e. RenderWare) components of the
* application in a polite fashion.
*/
static void
TidyUp3D()
{
/*
* Destroy the scene. This will destroy the contents of the scene,
* i.e. any clumps and lights in that scene. In this case destroying
* the scene will destroy the light we created in Init3D, and any
* clumps we have loaded and not already destroyed.
*/
RwDestroyScene(Scene);
/*
* Destroy the camera.
*/
RwDestroyCamera(Camera);
/*
* Close the library. This will free up any internal resources and
* textures loaded.
*/
RwClose();
}
/**********************************************************************/
/*
* This functions handles the left mouse button going down. Its main
* job is to determine the kind of action to be taken when the mouse
* moves, such as spinning a clump, or panning the camera. This involves
* examining the virtual keys that were depressed when the mouse button
* went down and attempting to pick a clump under the mouse pointer
* position.
*/
static void
HandleLeftButtonDown(int x, int y, int vKeys)
{
/* Stop warnings */
vKeys = vKeys;
x=x;
y=y;
nGFireCount=FIRE_FRAMES;
}
/**********************************************************************/
/*
* This functions handles the right mouse button going down. Its main
* job is to determine the kind of action to be taken when the mouse
* moves such as panning the camera.
*/
static void
HandleRightButtonDown(int x, int y, int vKeys)
{
/* Stop warnings */
x=x;
y=y;
vKeys=vKeys;
}
/**********************************************************************/
/*
* Handle the left mouse button comming back up. The basic action is
* to turn off mouse move actions and release mouse capture.
*/
static void
HandleLeftButtonUp(void)
{
}
/**********************************************************************/
/*
* Handle the right mouse button comming back up. The basic action is
* to turn of mouse move actions and release mouse capture.
*/
static void
HandleRightButtonUp(void)
{
}
/**********************************************************************/
/*
* Handle MS Window's timer expiry. This function will perform any
* animation actions necessary, including spinning clumps and animating
* textures.
*/
static void
HandleTimer(void) {
/*
* Animate textures. Enumerate over all the textures in the texture
* dictionary stack calling RwTextureNextFrame() to bump the
* current frame pointer of each texture. For single frame textures
* this is a no-op.
*/
RwForAllNamedTextures(RwTextureNextFrame);
/*
* See the description of HandlePaint() for a description of this common
* RenderWare cliche for rendering a scene and copying it to the display.
*/
RwBeginCameraUpdate(Camera,NULL);
RwUndamageCameraViewport(Camera,0,0,nGScrWidth,nGScrHeight-24);
RwDamageCameraViewport(Camera,(nGScrWidth>>1)-HOLE_RADIUS,
((nGScrHeight-24)>>1)-HOLE_RADIUS,
(nGScrWidth>>1)+HOLE_RADIUS,
((nGScrHeight-24)>>1)+HOLE_RADIUS);
RwClearCameraViewport(Camera);
RwRenderScene(Scene);
RwEndCameraUpdate(Camera);
RwShowCameraImage(Camera, NULL);
nGFrameNumber++;
}
/****************************************************************************
AddPolyStruct
On entry : Polygon
: pointer to polygon data structure
On exit :
*/
RwPolygon3d *AddPolyStruct(RwPolygon3d *pPoly,void *pData);
RwPolygon3d *AddPolyStruct(RwPolygon3d *pPoly,void *pData)
{
int nRow,nCol;
Tube *tpTube = (Tube *)pData;
nCol = RwGetPolygonTag(pPoly)%tpTube->nWidth;
nRow = RwGetPolygonTag(pPoly)-nCol;
tpTube->paPolyData[nRow*2+nCol] = pPoly;
tpTube->paPolyData[nRow*2+tpTube->nWidth+nCol] = pPoly;
return NULL;
}
/****************************************************************************
CreatePolyStruct
On entry : Clump to extract
On exit :
*/
void CreatePolyStruct(Tube *tpTube)
{
int nCount;
tpTube->ppaPoly =
(RwPolygon3d ***)malloc(sizeof(RwPolygon3d *)*(tpTube->nDepth-1));
tpTube->paPolyData = (RwPolygon3d **)
malloc(sizeof(RwPolygon3d *)*(tpTube->nWidth*2)*(tpTube->nDepth-1));
for(nCount=0;nCount<tpTube->nDepth-1;nCount++) {
tpTube->ppaPoly[nCount] = &(tpTube->paPolyData[nCount*tpTube->nWidth*2]);
};
RwForAllPolygonsInClumpPointer(tpTube->cpTube,AddPolyStruct,(void*)tpTube);
}
/****************************************************************************
Create Tube
On entry : Amount of sides
: Size
: Angle change
On exit :
*/
void CreateTube(Tube *tpTube)
{
int nCount,nCount2,nPolyNo;
RwReal nOffAngPos;
short int nStart;
RwClump *cpClump;
nPolyNo=0;
RwModelBegin();
RwClumpBegin();
RwSetSurfaceColor(CREAL(1.0),CREAL(0.5),CREAL(0.0));
RwSetSurface(CREAL(0.3),CREAL(0.4),CREAL(0.1));
RwSetSurfaceLightSampling(rwFACET);
RwSetSurfaceGeometrySampling(rwSOLID);
RwSetHints(rwCONTAINER);
nOffAngPos=CREAL(0.0);
RwTransformBegin();
RwIdentityCTM();
RwTranslateCTM(CREAL(0),CREAL(0),
-RDiv(RMul(tpTube->nSegLength,INT2REAL(tpTube->nDepth-1)),INT2REAL(2)) );
for (nCount=0;nCount<tpTube->nDepth;nCount++) {
RwTransformBegin();
for (nCount2=0;nCount2<tpTube->nWidth-1;nCount2++) {
RwTransformBegin();
RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
RDiv(RMul(CREAL(360.0),INT2REAL(nCount2)),INT2REAL(tpTube->nWidth)));
RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos);
RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
RwTransformEnd();
RwTransformBegin();
RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
RDiv(RMul(CREAL(360.0),INT2REAL(nCount2+1)),INT2REAL(tpTube->nWidth)));
RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos);
RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
RwTransformEnd();
RwTransformBegin();
RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
RDiv(RMul(CREAL(360.0),INT2REAL(nCount2+1)),INT2REAL(tpTube->nWidth)));
RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos+tpTube->nOffAngle);
RwTranslateCTM(0,0,tpTube->nSegLength);
RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
RwTransformEnd();
RwTransformBegin();
RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
RDiv(RMul(CREAL(360.0),INT2REAL(nCount2)),INT2REAL(tpTube->nWidth)));
RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos+tpTube->nOffAngle);
RwTranslateCTM(0,0,tpTube->nSegLength);
RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
RwTransformEnd();
};
RwTransformBegin();
RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
RDiv(RMul(CREAL(360.0),INT2REAL(nCount2)),INT2REAL(tpTube->nWidth)));
RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos);
RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
RwTransformEnd();
RwTransformBegin();
RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos);
RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
RwTransformEnd();
RwTransformBegin();
RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos+tpTube->nOffAngle);
RwTranslateCTM(0,0,tpTube->nSegLength);
RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
RwTransformEnd();
RwTransformBegin();
RwRotateCTM(CREAL(0.0),CREAL(0.0),CREAL(1.0),
RDiv(RMul(CREAL(360.0),INT2REAL(nCount2)),INT2REAL(tpTube->nWidth)));
RwRotateCTM(CREAL(0),CREAL(0),CREAL(1),nOffAngPos+tpTube->nOffAngle);
RwTranslateCTM(0,0,tpTube->nSegLength);
RwVertex(CREAL(0.0),tpTube->nSize,CREAL(0.0) );
RwTransformEnd();
RwTransformEnd();
RwTranslateCTM(CREAL(0),CREAL(0),tpTube->nSegLength);
nOffAngPos=RAdd(nOffAngPos,tpTube->nOffAngle);
};
RwTransformEnd();
nStart =1;
for (nCount=0;nCount<tpTube->nDepth-1;nCount++) {
for (nCount2=0;nCount2<tpTube->nWidth;nCount2++) {
RwQuadExt(nStart+3,nStart+2,nStart+1,nStart,nPolyNo);
nPolyNo++;
nStart+=4;
};
};
RwClumpEnd(&cpClump);
RwModelEnd();
RwSetClumpData(cpClump,NULL); /* Mark as NULL */
tpTube->cpTube = cpClump;
tpTube->mpTubeRot = RwCreateMatrix();
RwRotateMatrix(tpTube->mpTubeRot,CREAL(0),CREAL(0),CREAL(1.0),
CREAL(-2.0),rwREPLACE);
RwIdentityMatrix(tpTube->mpTubePos = RwCreateMatrix());
tpTube->mpTubeFlip = RwCreateMatrix();
RwRotateMatrix(tpTube->mpTubeFlip,CREAL(0),CREAL(0),CREAL(1.0),
-tpTube->nOffAngle,rwREPLACE);
RwPushScratchMatrix();
RwMultiplyMatrix(tpTube->mpTubeFlip,tpTube->mpTubeRot,RwScratchMatrix());
RwCopyMatrix(RwScratchMatrix(),tpTube->mpTubeFlip);
RwPopScratchMatrix();
tpTube->vTubePos.x=CREAL(0.0);
tpTube->vTubePos.y=CREAL(0.0);
tpTube->vTubePos.z=CREAL(0.0);
tpTube->nStepSize = RDiv(tpTube->nSegLength,INT2REAL(tpTube->nSteps));
tpTube->nCurStep=0;
tpTube->nStepPos = CREAL(0.0);
CreatePolyStruct(tpTube);
tpTube->DispTextures.nDisp = 5;
SetTexture(tpTube);
}
/****************************************************************************
ScrollPolys
On entry :
On exit :
*/
void ScrollPolys(Tube *tpTube)
{
int nCount;
int nCount2;
RwUV uvaVertex[4];
for (nCount=tpTube->nDepth-3;nCount>=0;nCount--) {
for (nCount2=0;nCount2<tpTube->nWidth;nCount2++) {
RwSetPolygonMaterial(tpTube->ppaPoly[nCount+1][nCount2],
RwGetPolygonMaterial(tpTube->ppaPoly[nCount][nCount2]));
RwGetPolygonUV(tpTube->ppaPoly[nCount][nCount2],uvaVertex);
RwSetPolygonUV(tpTube->ppaPoly[nCount+1][nCount2],uvaVertex);
};
};
}
/****************************************************************************
SetTexture
On entry
On exit :
*/
void SetTexture(Tube *tpTube)
{
Textures *tpTex = &tpTube->DispTextures;
int nValue;
nValue = rand();
tpTex->nCount=(nValue&3)+2;
tpTex->nTexWidth=((nValue>>2)&3)+1;
tpTex->nTexHeight=((nValue>>4)&3)+1;
tpTex->nX = (nValue>>8)&7;
tpTex->nY = 0;
tpTex->nTexture++;
if (tpTex->nTexture>tpTex->nAmoTextures) {
tpTex->nTexture=0;
};
}
/****************************************************************************
RingForeshorten
*/
void RingForeshorten(Tube *tpTube)
{
int nCount;
for (nCount=0;nCount<tpTube->nWidth;nCount++) {
RwSetPolygonTextureModes(tpTube->ppaPoly[FORESHORT_RING][nCount],
rwFORESHORTEN);
};
};
/****************************************************************************
AddTexture
On entry : Tube Structure
On exit :
*/
void AddTexture(Tube *tpTube)
{
Textures *tpTex;
RwUV uvaVertex[4];
int nCount;
tpTex = &tpTube->DispTextures;
if (!tpTex->nCount) {
/* Have to do some displaying stuff */
for (nCount=0;nCount<(tpTex->nTexWidth);nCount++) {
RwSetPolygonTextureModes(tpTube->ppaPoly[0][nCount+tpTex->nX],0);
RwSetPolygonTexture(tpTube->ppaPoly[0][nCount+tpTex->nX],
tpTex->taTextures[tpTex->nTexture]);
uvaVertex[0].u=RDiv(INT2REAL(nCount),INT2REAL(tpTex->nTexWidth));
uvaVertex[0].v=RDiv(INT2REAL(tpTex->nY),INT2REAL(tpTex->nTexHeight));
uvaVertex[1].u=RDiv(INT2REAL(nCount+1),INT2REAL(tpTex->nTexWidth));
uvaVertex[1].v=RDiv(INT2REAL(tpTex->nY),INT2REAL(tpTex->nTexHeight));
uvaVertex[2].u=RDiv(INT2REAL(nCount+1),INT2REAL(tpTex->nTexWidth));
uvaVertex[2].v=RDiv(INT2REAL(tpTex->nY+1),INT2REAL(tpTex->nTexHeight));
uvaVertex[3].u=RDiv(INT2REAL(nCount),INT2REAL(tpTex->nTexWidth));
uvaVertex[3].v=RDiv(INT2REAL(tpTex->nY+1),INT2REAL(tpTex->nTexHeight));
RwSetPolygonUV(tpTube->ppaPoly[0][nCount+tpTex->nX],uvaVertex);
};
tpTex->nY++;
if (tpTex->nY>=tpTex->nTexHeight) {
SetTexture(tpTube);
};
} else {
tpTex->nCount--;
};
}
/****************************************************************************
UpdateTube
On entry : Tube to be updated
On exit :
*/
void UpdateTube(Tube *tpTube,Ring *rpRing)
{
int nValue;
HandleRings(tpTube,rpRing);
RwPushScratchMatrix();
if (tpTube->nCurStep<tpTube->nSteps) {
RwMultiplyMatrix(tpTube->mpTubePos,tpTube->mpTubeRot,RwScratchMatrix());
if (!(nGFrameNumber&127)) {
RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
};
RwCopyMatrix(RwScratchMatrix(),tpTube->mpTubePos);
} else {
tpTube->nCurStep=0;
tpTube->nStepPos=CREAL(0.0);
RwMultiplyMatrix(tpTube->mpTubePos,tpTube->mpTubeFlip,RwScratchMatrix());
if (!(nGFrameNumber&127)) {
RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
};
RwCopyMatrix(RwScratchMatrix(), tpTube->mpTubePos);
ScrollPolys(tpTube);
ScrollRings(tpTube,rpRing);
nValue=rand();
switch (nValue&7) {
case 0:
case 3:
case 5: {
CreateRingCheck(tpTube,rpRing,caGColors[(nValue>>8)&nGColorMask]);
break;
};
case 2: {
CreateRingRotate(tpTube,rpRing,
caGColors[(nValue>>8)&nGColorMask],
caGColors[(3+(nValue>>8))&nGColorMask],((nValue>>5)&2)-1) ;
break;
};
default: {
CreateRingColor(tpTube,rpRing,
caGColors[(nValue>>8)&nGColorMask]);
break;
};
};
AddTexture(tpTube);
};
RingForeshorten(tpTube);
RwTranslateMatrix(RwScratchMatrix(),
tpTube->vTubePos.x,
tpTube->vTubePos.y,
RAdd(tpTube->vTubePos.z,tpTube->nStepPos)
, rwPOSTCONCAT);
RwTransformClump(tpTube->cpTube, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
tpTube->nCurStep++;
tpTube->nStepPos+=tpTube->nStepSize;
}
/****************************************************************************
SetTubeColor
*/
void SetTubeColor(Tube *tpTube,RwRGBColor cCol)
{
int nCount;
for (nCount=0;nCount<tpTube->nWidth;nCount++) {
RwSetPolygonColor(tpTube->ppaPoly[0][nCount],
cCol.r,cCol.g,cCol.b);
RwSetPolygonTexture(tpTube->ppaPoly[0][nCount],NULL);
};
}
/****************************************************************************
CreateRingColor
On entry : Color
*/
void CreateRingColor(Tube *tpTube,Ring *rpRing,RwRGBColor cColA)
{
SetTubeColor(tpTube,cColA);
rpRing->raRings[0].nType = RING_COLOR;
}
/****************************************************************************
CreateRingCheck
On entry : Color
*/
void CreateRingCheck(Tube *tpTube,Ring *rpRing,RwRGBColor cColA)
{
RwRGBColor cColB;
int nCount;
cColB.r = RDiv(cColA.r,CREAL(4.0));
cColB.g = RDiv(cColA.g,CREAL(4.0));
cColB.b = RDiv(cColA.b,CREAL(4.0));
for (nCount=0;nCount<tpTube->nWidth;nCount++) {
if (nCount&1) {
RwSetPolygonColor(tpTube->ppaPoly[0][nCount],
cColA.r,cColA.g,cColA.b);
} else {
RwSetPolygonColor(tpTube->ppaPoly[0][nCount],
cColB.r,cColB.g,cColB.b);
};
RwSetPolygonTexture(tpTube->ppaPoly[0][nCount],NULL);
};
rpRing->raRings[0].nType = RING_COLOR;
}
/****************************************************************************
CreateRingRotate
On entry : Colour A
: Colour B
: Direction
On exit :
*/
void CreateRingRotate(Tube *tpTube,Ring *rpRing,
RwRGBColor cColA,RwRGBColor cColB,int nDir)
{
RingData *rdpR;
rdpR = &rpRing->raRings[0];
rdpR->nType = RING_ROTATE;
rdpR->cColA = cColA;
rdpR->cColB = cColB;
rdpR->nParam1 = 0;
rdpR->nParam2 = nDir;
SetTubeColor(tpTube,cColA);
}
/****************************************************************************
HandleRings
*/
void HandleRings(Tube *tpTube,Ring *rpRing)
{
int nCount;
RingData *rdpR;
for (nCount=0;nCount<tpTube->nDepth-1;nCount++) {
rdpR = &rpRing->raRings[nCount];
switch (rdpR->nType) {
case RING_COLOR: {
break;
};
case RING_ROTATE: {
RwSetPolygonColor(tpTube->ppaPoly[nCount][rdpR->nParam1],
rdpR->cColA.r,rdpR->cColA.g,rdpR->cColA.b);
rdpR->nParam1+=rdpR->nParam2;
if (rdpR->nParam1>tpTube->nWidth-1) {
rdpR->nParam1=0;
};
if (rdpR->nParam1<0) {
rdpR->nParam1 = tpTube->nWidth-1;
};
RwSetPolygonColor(tpTube->ppaPoly[nCount][rdpR->nParam1],
rdpR->cColB.r,rdpR->cColB.g,rdpR->cColB.b);
break;
};
};
};
}
/****************************************************************************
ScrollRings
On entry :
On exit :
*/
void ScrollRings(Tube *tpTube,Ring *rpRing)
{
int nCount;
for (nCount=tpTube->nDepth-3;nCount>=0;nCount--) {
rpRing->raRings[nCount+1] = rpRing->raRings[nCount];
};
}
/****************************************************************************
CreateTextures
On entry : Texture structure
On exit :
*/
void CreateTextures(Textures *tpTextures)
{
char saTextureFiles[][14]={
"mandel",
"bird",
"face",
"marble",
"marble",
"wood",
"rust"};
int nCount;
tpTextures->nAmoTextures = 7;
for (nCount=0;nCount<tpTextures->nAmoTextures;nCount++) {
tpTextures->taTextures[nCount] = RwReadNamedTexture(saTextureFiles[nCount]);
};
}
/****************************************************************************
Main
*/
void main(int nArgc,char *saArgv[])
{
int nKey;
int nMouseX,nMouseY,nMouseBut,nOldMouseBut,nOldMouseX,nOldMouseY;
int nChange;
int nStatus;
RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
RwReal naBlack[]={CREAL(0.0),CREAL(0.0),CREAL(0.0)};
int nWhite;
int nBlack;
RwReal nPointX;
RwReal nPointY;
RwImageConvert ciConvert;
RwPointerImage piImage;
RwClump *cpHit;
Object *opHit;
int nSpeed;
char *cpTmp;
int nCtrlShift=0;
int nGeo = FALSE;
int nCount;
/* Default speed */
nSpeed = 8;
/* Parse the command line */
for (nCount=1;nCount<nArgc;nCount++) {
if (!strcmp("-o",saArgv[nCount])) {
nGeo = TRUE;
} else {
cpTmp = saArgv[nCount];
while ((*cpTmp>='0')&&(*cpTmp<='9')) {
cpTmp++;
};
if (!*cpTmp) {
nSpeed = atoi(saArgv[nCount]);
} else {
nArgc = 4;
break;
};
};
};
if (nArgc>=4) {
printf("Usage : %s [-o] [Speed]\n",saArgv[1]);
printf("Smaller is faster (1 fastest) 8 default\n");
printf("-o uses objects instead of simple geomety\n");
exit(1);
};
if (!Init3D(saArgv[0]))
{
exit(-1);
};
nWhite = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
nBlack = RwDeviceControl(rwSCRGETCOLOR,0,naBlack,sizeof(naBlack)),
/* Create the tube */
tGTube.nWidth = 8;
tGTube.nDepth = 18;
tGTube.nSegLength = CREAL(1.3);
tGTube.nSize = CREAL(1.0);
tGTube.nOffAngle = CREAL(10.0);
tGTube.nSteps=nSpeed;
CreateTube(&tGTube);
RwAddClumpToScene(Scene, tGTube.cpTube);
CreateTextures(&tGTube.DispTextures);
/* Set up the mouse pointers */
ciConvert.inimage = sGMouseArrow;
ciConvert.w = MOUSE_ARROW_W;
ciConvert.h = MOUSE_ARROW_H;
ciConvert.colora = nBlack;
ciConvert.colorb = nWhite;
ciConvert.outstorage = NULL;
RwDeviceControl(rwCHARMAPTORAW,0,&ciConvert,sizeof(ciConvert));
pGMouseArrow = ciConvert.outstorage;
ciConvert.inimage = sGMouseFire;
ciConvert.w = MOUSE_FIRE_W;
ciConvert.h = MOUSE_FIRE_H;
ciConvert.outstorage = NULL;
RwDeviceControl(rwCHARMAPTORAW,0,&ciConvert,sizeof(ciConvert));
pGMouseFire = ciConvert.outstorage;
ciConvert.inimage = sGMouseSight;
ciConvert.w = MOUSE_SIGHT_W;
ciConvert.h = MOUSE_SIGHT_H;
ciConvert.outstorage = NULL;
RwDeviceControl(rwCHARMAPTORAW,0,&ciConvert,sizeof(ciConvert));
pGMouseSight = ciConvert.outstorage;
/* Creation of objects */
AllObjectsCreate(&aoGObjects);
StackObjectsCreate(&aoGObjects.sObjects,nGeo);
StackExplosionCreate(&aoGObjects.sExplosion);
LaunchCreate(&lGLaunch,40);
/* Create pointer */
RwDPointerDisplay(&nOldMouseX,&nOldMouseY,&nOldMouseBut);
nKey = DosGetKey();
nStatus =0;
while (nKey!=27) { /* ESC quits */
RwDPointerDisplay(&nMouseX,&nMouseY,&nMouseBut);
if (nGFireCount) {
nGFireCount--;
};
nGPickStatus = 0;
if (nMouseY<nGScrHeight-24) {
if (RwPickScene(Scene, nMouseX, nMouseY, Camera, &pGPick)) {
if (pGPick.type==rwPICKCLUMP) {
cpHit = pGPick.object.clump.clump;
opHit =(Object *)RwGetClumpData(cpHit);
if (opHit) {
nGPickStatus = 1;
/* Explode the object */
piImage.hotx = MOUSE_FIRE_X;
piImage.hoty = MOUSE_FIRE_Y;
piImage.w = MOUSE_FIRE_W;
piImage.h = MOUSE_FIRE_H;
piImage.image= pGMouseFire;
RwDeviceControl(rwPOINTERSETIMAGE,0,&piImage,sizeof(piImage));
if (nGFireCount) {
/* Explode the object */
CreateExplosion
(&aoGObjects,&opHit->vPos,&opHit->vVel,EXPLOSION_BITS);
AllObjectsRemove(&aoGObjects,&aoGObjects.sObjects,opHit);
};
};
};
};
};
if (!nGPickStatus) {
piImage.hotx = MOUSE_SIGHT_X;
piImage.hoty = MOUSE_SIGHT_Y;
piImage.w = MOUSE_SIGHT_W;
piImage.h = MOUSE_SIGHT_H;
piImage.image= pGMouseSight;
RwDeviceControl(rwPOINTERSETIMAGE,0,&piImage,sizeof(piImage));
};
UpdateTube(&tGTube,&rGRing);
/* The other bits */
nPointX = RDiv(INT2REAL(nMouseX-(nGScrWidth>>1)),
INT2REAL((nGScrWidth>>1)));
if (nMouseY<=nGScrHeight-24) {
nPointY = RDiv(INT2REAL(nMouseY-((nGScrHeight-24)>>1)),
INT2REAL((nGScrHeight-24)>>1));
} else {
nPointY = CREAL(1.0);
};
RwSetCameraPosition(Camera,RMul(nPointX,CREAL(0.58)),
-RMul(nPointY,CREAL(0.58)),-DEFAULT_CAMERA_DISTANCE);
nKey = DosGetKey();
nChange = (nMouseBut&(2+8)) | ( (nOldMouseBut&(2+8)) >>1 );
switch (nChange) {
case 0+0:
case 2+1:
case 8+4:
case 8+2+4+1: {
/* No change */
break;
};
case 2:
case 8+2+4: {
/* Left Button Down */
HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
break;
};
case 8:
case 8+2+1: {
/* Right Button Down */
HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
break;
};
case 8+1: {
/* Right down left Up */
HandleLeftButtonUp();
HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
break;
};
case 2+4: {
/* Right up left Down */
HandleRightButtonUp();
HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
break;
};
case 8+2: {
/* Left down RIght Down */
HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
break;
};
case 1+4: {
/* Left up Right Up */
HandleRightButtonUp();
HandleLeftButtonUp();
break;
};
case 1:
case 8+4+1: {
/* Left up */
HandleLeftButtonUp();
break;
};
case 4:
case 2+4+1: {
/* Right up */
HandleRightButtonUp();
break;
};
};
EnemyLaunchHandler(&lGLaunch,&aoGObjects);
AllObjectsUpdate(&aoGObjects);
HandleTimer();
nOldMouseX = nMouseX;
nOldMouseY = nMouseY;
nOldMouseBut = nMouseBut;
};
/*
* Tidy up the 3D (RenderWare) components of the application.
*/
TidyUp3D();
exit(0);
}