1149 lines
22 KiB
C
1149 lines
22 KiB
C
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <vfw.h>
|
||
|
|
||
|
#include <gldd.h>
|
||
|
#include <gl/glu.h>
|
||
|
#include <gl/glaux.h>
|
||
|
|
||
|
#define PI 3.14159265358979323846
|
||
|
|
||
|
#define NLETTERS 64
|
||
|
#define FIRST_LETTER '@'
|
||
|
|
||
|
#define NOBJS 6
|
||
|
|
||
|
GLenum doubleBuffer;
|
||
|
GLenum videoMemory;
|
||
|
GLenum noSwap;
|
||
|
GLenum noClear;
|
||
|
GLenum fullScreen;
|
||
|
GLenum useMcd;
|
||
|
GLenum modeX;
|
||
|
GLenum stretch;
|
||
|
GLenum paletted;
|
||
|
GLenum timings;
|
||
|
GLenum spin;
|
||
|
|
||
|
GLenum updateMovie = GL_TRUE;
|
||
|
GLenum linearFilter = GL_FALSE;
|
||
|
|
||
|
int fullWidth, fullHeight, fullDepth;
|
||
|
int winWidth, winHeight;
|
||
|
int texWidth, texHeight;
|
||
|
int movX, movY;
|
||
|
int movWidth, movHeight;
|
||
|
GLuint clearBits;
|
||
|
DWORD ticks;
|
||
|
int frames;
|
||
|
|
||
|
GLint letters;
|
||
|
GLYPHMETRICSFLOAT letterMetrics[NLETTERS];
|
||
|
|
||
|
double xrot, yrot;
|
||
|
|
||
|
GLDDWINDOW gwMain = NULL;
|
||
|
|
||
|
PFNGLCOLORTABLEEXTPROC pfnColorTableEXT;
|
||
|
PFNGLCOLORSUBTABLEEXTPROC pfnColorSubTableEXT;
|
||
|
|
||
|
LPDIRECTDRAWSURFACE pddsTex;
|
||
|
DDSURFACEDESC ddsdTex;
|
||
|
|
||
|
char *aviFileName = "d:\\winnt\\clock.avi";
|
||
|
PAVISTREAM aviStream;
|
||
|
long aviLength;
|
||
|
long curFrame;
|
||
|
PGETFRAME aviGetFrame;
|
||
|
BITMAPINFO *pbmiMovie;
|
||
|
|
||
|
typedef struct _Object
|
||
|
{
|
||
|
void (*build_fn)(void);
|
||
|
GLenum canCull;
|
||
|
GLenum needsZ;
|
||
|
GLint dlist;
|
||
|
} Object;
|
||
|
|
||
|
int objIdx = 0;
|
||
|
|
||
|
float c[6][4][3] = {
|
||
|
{
|
||
|
{
|
||
|
1.0f, 1.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
-1.0f, 1.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
-1.0f, -1.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -1.0f, -1.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
1.0f, 1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, 1.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -1.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -1.0f, 1.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
-1.0f, 1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, 1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-1.0f, -1.0f, 1.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
-1.0f, 1.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
-1.0f, 1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-1.0f, -1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-1.0f, -1.0f, -1.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
-1.0f, 1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-1.0f, 1.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, 1.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, 1.0f, 1.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
-1.0f, -1.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
-1.0f, -1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -1.0f, -1.0f
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
float n[6][3] = {
|
||
|
{
|
||
|
0.0f, 0.0f, -1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, 0.0f, 0.0f
|
||
|
},
|
||
|
{
|
||
|
0.0f, 0.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-1.0f, 0.0f, 0.0f
|
||
|
},
|
||
|
{
|
||
|
0.0f, 1.0f, 0.0f
|
||
|
},
|
||
|
{
|
||
|
0.0f, -1.0f, 0.0f
|
||
|
}
|
||
|
};
|
||
|
|
||
|
float t[6][4][2] = {
|
||
|
{
|
||
|
{
|
||
|
1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, -0.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -0.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, -0.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -0.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
-0.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -0.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, -0.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, -0.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -0.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, -0.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -0.0f
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
{
|
||
|
1.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, 1.0f
|
||
|
},
|
||
|
{
|
||
|
-0.0f, -0.0f
|
||
|
},
|
||
|
{
|
||
|
1.0f, -0.0f
|
||
|
}
|
||
|
},
|
||
|
};
|
||
|
|
||
|
void BuildSphere(void)
|
||
|
{
|
||
|
GLUquadricObj *quadObj;
|
||
|
|
||
|
quadObj = gluNewQuadric ();
|
||
|
gluQuadricDrawStyle (quadObj, GLU_FILL);
|
||
|
gluQuadricNormals (quadObj, GLU_SMOOTH);
|
||
|
gluQuadricTexture (quadObj, GL_TRUE);
|
||
|
gluSphere (quadObj, 1.0, 16, 16);
|
||
|
gluDeleteQuadric(quadObj);
|
||
|
}
|
||
|
|
||
|
void BuildCube(void)
|
||
|
{
|
||
|
GLint i;
|
||
|
|
||
|
for (i = 0; i < 6; i++)
|
||
|
{
|
||
|
glBegin(GL_POLYGON);
|
||
|
glNormal3fv(n[i]); glTexCoord2fv(t[i][0]); glVertex3fv(c[i][0]);
|
||
|
glNormal3fv(n[i]); glTexCoord2fv(t[i][3]); glVertex3fv(c[i][3]);
|
||
|
glNormal3fv(n[i]); glTexCoord2fv(t[i][2]); glVertex3fv(c[i][2]);
|
||
|
glNormal3fv(n[i]); glTexCoord2fv(t[i][1]); glVertex3fv(c[i][1]);
|
||
|
glEnd();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BuildCylinder(void)
|
||
|
{
|
||
|
GLUquadricObj *quadObj;
|
||
|
|
||
|
glPushMatrix ();
|
||
|
glRotatef ((GLfloat)90.0, (GLfloat)1.0, (GLfloat)0.0, (GLfloat)0.0);
|
||
|
glTranslatef ((GLfloat)0.0, (GLfloat)0.0, (GLfloat)-1.0);
|
||
|
quadObj = gluNewQuadric ();
|
||
|
gluQuadricDrawStyle (quadObj, GLU_FILL);
|
||
|
gluQuadricTexture (quadObj, GL_TRUE);
|
||
|
gluCylinder (quadObj, 1.0, 1.0, 1.5, 20, 2);
|
||
|
glPopMatrix ();
|
||
|
gluDeleteQuadric(quadObj);
|
||
|
}
|
||
|
|
||
|
void BuildCone(void)
|
||
|
{
|
||
|
GLUquadricObj *quadObj;
|
||
|
|
||
|
quadObj = gluNewQuadric ();
|
||
|
gluQuadricDrawStyle (quadObj, GLU_FILL);
|
||
|
gluQuadricTexture (quadObj, GL_TRUE);
|
||
|
gluCylinder (quadObj, 1.0, 0.0, 1.5, 20, 2);
|
||
|
gluDeleteQuadric(quadObj);
|
||
|
}
|
||
|
|
||
|
void BuildTeapot(void)
|
||
|
{
|
||
|
auxSolidTeapot(1.0);
|
||
|
}
|
||
|
|
||
|
#define STRING "OpenGL"
|
||
|
|
||
|
void BuildString(void)
|
||
|
{
|
||
|
char *str;
|
||
|
int i, l;
|
||
|
float wd, ht;
|
||
|
GLfloat fv4[4];
|
||
|
|
||
|
str = STRING;
|
||
|
l = strlen(str);
|
||
|
|
||
|
wd = 0.0f;
|
||
|
for (i = 0; i < l-1; i++)
|
||
|
{
|
||
|
wd += letterMetrics[str[i]-FIRST_LETTER].gmfCellIncX;
|
||
|
}
|
||
|
wd += letterMetrics[str[i]-FIRST_LETTER].gmfBlackBoxX;
|
||
|
ht = letterMetrics[str[0]-FIRST_LETTER].gmfBlackBoxY;
|
||
|
|
||
|
glPushMatrix();
|
||
|
|
||
|
glScalef(1.0f, 2.0f, 1.0f);
|
||
|
glTranslatef(-wd/2.0f, -ht/2.0f, 0.0f);
|
||
|
|
||
|
fv4[0] = 1.0f/wd;
|
||
|
fv4[1] = 0.0f;
|
||
|
fv4[2] = 0.0f;
|
||
|
fv4[3] = 0.0f;
|
||
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
|
||
|
glTexGenfv(GL_S, GL_EYE_PLANE, fv4 );
|
||
|
|
||
|
fv4[0] = 0.0f;
|
||
|
fv4[1] = -1.0f/ht;
|
||
|
fv4[2] = 0.0f;
|
||
|
fv4[3] = 0.0f;
|
||
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
|
||
|
glTexGenfv(GL_T, GL_EYE_PLANE, fv4 );
|
||
|
|
||
|
glEnable(GL_TEXTURE_GEN_S);
|
||
|
glEnable(GL_TEXTURE_GEN_T);
|
||
|
|
||
|
glListBase(letters-FIRST_LETTER);
|
||
|
glCallLists(l, GL_UNSIGNED_BYTE, str);
|
||
|
|
||
|
glListBase(0);
|
||
|
glPopMatrix();
|
||
|
glDisable(GL_TEXTURE_GEN_S);
|
||
|
glDisable(GL_TEXTURE_GEN_T);
|
||
|
}
|
||
|
|
||
|
Object objects[NOBJS] =
|
||
|
{
|
||
|
BuildCube, GL_TRUE, GL_FALSE, 0,
|
||
|
BuildSphere, GL_TRUE, GL_FALSE, 0,
|
||
|
BuildCylinder, GL_FALSE, GL_TRUE, 0,
|
||
|
BuildCone, GL_FALSE, GL_TRUE, 0,
|
||
|
BuildTeapot, GL_FALSE, GL_TRUE, 0,
|
||
|
BuildString, GL_TRUE, GL_TRUE, 0,
|
||
|
};
|
||
|
|
||
|
void BuildLists(void)
|
||
|
{
|
||
|
int i;
|
||
|
GLint base;
|
||
|
|
||
|
base = glGenLists(NOBJS);
|
||
|
for (i = 0; i < NOBJS; i++)
|
||
|
{
|
||
|
objects[i].dlist = base+i;
|
||
|
glNewList(objects[i].dlist, GL_COMPILE);
|
||
|
objects[i].build_fn();
|
||
|
glEndList();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Quit(char *fmt, ...)
|
||
|
{
|
||
|
va_list args;
|
||
|
|
||
|
if (fmt != NULL)
|
||
|
{
|
||
|
va_start(args, fmt);
|
||
|
vprintf(fmt, args);
|
||
|
va_end(args);
|
||
|
}
|
||
|
|
||
|
if (aviGetFrame != NULL)
|
||
|
{
|
||
|
AVIStreamGetFrameClose(aviGetFrame);
|
||
|
}
|
||
|
|
||
|
if (aviStream != NULL)
|
||
|
{
|
||
|
AVIStreamRelease(aviStream);
|
||
|
AVIFileExit();
|
||
|
}
|
||
|
|
||
|
if (gwMain != NULL)
|
||
|
{
|
||
|
glddDestroyWindow(gwMain);
|
||
|
}
|
||
|
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
void Draw(void)
|
||
|
{
|
||
|
DWORD fticks;
|
||
|
|
||
|
fticks = GetTickCount();
|
||
|
|
||
|
glClear(clearBits);
|
||
|
|
||
|
glLoadIdentity();
|
||
|
glRotated(xrot, 1.0, 0.0, 0.0);
|
||
|
glRotated(yrot, 0.0, 1.0, 0.0);
|
||
|
|
||
|
glCallList(objects[objIdx].dlist);
|
||
|
|
||
|
glFlush();
|
||
|
if (doubleBuffer && !noSwap)
|
||
|
{
|
||
|
glddSwapBuffers(gwMain);
|
||
|
}
|
||
|
|
||
|
ticks += GetTickCount()-fticks;
|
||
|
frames++;
|
||
|
|
||
|
if (timings && ticks > 1000)
|
||
|
{
|
||
|
printf("%d frames in %d ticks, %.3lf f/s\n", frames, ticks,
|
||
|
(double)frames*1000.0/ticks);
|
||
|
frames = 0;
|
||
|
ticks = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void *UpdateBmi(BITMAPINFO *pbmi)
|
||
|
{
|
||
|
if (pbmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER))
|
||
|
{
|
||
|
Quit("Unknown stream format data\n");
|
||
|
}
|
||
|
|
||
|
memcpy(pbmiMovie->bmiColors, pbmi->bmiColors, 256*sizeof(RGBQUAD));
|
||
|
|
||
|
// Return pointer to data after BITMAPINFO
|
||
|
return pbmi->bmiColors+256;
|
||
|
}
|
||
|
|
||
|
void FrameToTex(long frame)
|
||
|
{
|
||
|
HDC hdc;
|
||
|
HRESULT hr;
|
||
|
LPVOID pvFrame, pvData;
|
||
|
|
||
|
pvFrame = AVIStreamGetFrame(aviGetFrame, frame);
|
||
|
if (pvFrame == NULL)
|
||
|
{
|
||
|
Quit("AVIStreamGetFrame failed\n");
|
||
|
}
|
||
|
|
||
|
// Skip past BITMAPINFO at start of frame.
|
||
|
// If it becomes interesting to support palette changes per frame
|
||
|
// this should call UpdateBmi
|
||
|
#if 0
|
||
|
pvData = (LPVOID)((BYTE *)pvFrame+sizeof(BITMAPINFO)+255*sizeof(RGBQUAD));
|
||
|
#else
|
||
|
pvData = UpdateBmi(pvFrame);
|
||
|
if (paletted)
|
||
|
{
|
||
|
pfnColorSubTableEXT(GL_TEXTURE_2D, 0, 256, GL_BGRA_EXT,
|
||
|
GL_UNSIGNED_BYTE, pbmiMovie->bmiColors);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (stretch)
|
||
|
{
|
||
|
hr = pddsTex->lpVtbl->GetDC(pddsTex, &hdc);
|
||
|
if (hr != DD_OK)
|
||
|
{
|
||
|
Quit("Stretch GetDC failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
|
||
|
StretchDIBits(hdc, 0, 0, texWidth, texHeight,
|
||
|
0, 0, movWidth, movHeight, pvData, pbmiMovie,
|
||
|
DIB_RGB_COLORS, SRCCOPY);
|
||
|
|
||
|
pddsTex->lpVtbl->ReleaseDC(pddsTex, hdc);
|
||
|
}
|
||
|
else if (!paletted)
|
||
|
{
|
||
|
hr = pddsTex->lpVtbl->GetDC(pddsTex, &hdc);
|
||
|
if (hr != DD_OK)
|
||
|
{
|
||
|
Quit("Set GetDC failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
|
||
|
// The only AVI sources currently allowed are 8bpp so if the texture
|
||
|
// isn't paletted a conversion is necessary
|
||
|
SetDIBitsToDevice(hdc, movX, movY, movWidth, movHeight,
|
||
|
0, 0, 0, movHeight, pvData, pbmiMovie,
|
||
|
DIB_RGB_COLORS);
|
||
|
|
||
|
pddsTex->lpVtbl->ReleaseDC(pddsTex, hdc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UINT cbLine;
|
||
|
int y;
|
||
|
BYTE *pbSrc, *pbDst;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = pddsTex->lpVtbl->Lock(pddsTex, NULL, &ddsdTex,
|
||
|
DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
|
||
|
NULL);
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
Quit("Unable to lock texture, 0x%08lX\n", hr);
|
||
|
}
|
||
|
|
||
|
cbLine = (movWidth+3) & ~3;
|
||
|
pbSrc = (BYTE *)pvData;
|
||
|
pbDst = (BYTE *)ddsdTex.lpSurface+ddsdTex.lPitch*movY+movX;
|
||
|
|
||
|
#if 1
|
||
|
for (y = 0; y < movHeight; y++)
|
||
|
{
|
||
|
memcpy(pbDst, pbSrc, movWidth);
|
||
|
pbSrc += cbLine;
|
||
|
pbDst += ddsdTex.lPitch;
|
||
|
}
|
||
|
#else
|
||
|
for (y = 0; y < movHeight; y++)
|
||
|
{
|
||
|
memset(pbDst, y*256/movHeight, movWidth);
|
||
|
pbSrc += cbLine;
|
||
|
pbDst += ddsdTex.lPitch;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
pddsTex->lpVtbl->Unlock(pddsTex, ddsdTex.lpSurface);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Animate(GLDDWINDOW gw)
|
||
|
{
|
||
|
if (updateMovie)
|
||
|
{
|
||
|
if (++curFrame == aviLength)
|
||
|
{
|
||
|
curFrame = 0;
|
||
|
}
|
||
|
FrameToTex(curFrame);
|
||
|
}
|
||
|
|
||
|
if (spin)
|
||
|
{
|
||
|
xrot += 2;
|
||
|
yrot += 3;
|
||
|
}
|
||
|
|
||
|
Draw();
|
||
|
}
|
||
|
|
||
|
void SetView(void)
|
||
|
{
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadIdentity();
|
||
|
gluPerspective(45.0, (double)winWidth/winHeight, 0.1, 10);
|
||
|
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
}
|
||
|
|
||
|
void ToggleGl(GLenum state)
|
||
|
{
|
||
|
if (glIsEnabled(state))
|
||
|
{
|
||
|
glDisable(state);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glEnable(state);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SetObject(int idx)
|
||
|
{
|
||
|
objIdx = idx;
|
||
|
|
||
|
clearBits = GL_COLOR_BUFFER_BIT;
|
||
|
|
||
|
if (objects[objIdx].canCull)
|
||
|
{
|
||
|
glFrontFace(GL_CCW);
|
||
|
glCullFace(GL_BACK);
|
||
|
glEnable(GL_CULL_FACE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glDisable(GL_CULL_FACE);
|
||
|
}
|
||
|
|
||
|
if (objects[objIdx].needsZ)
|
||
|
{
|
||
|
clearBits |= GL_DEPTH_BUFFER_BIT;
|
||
|
glEnable(GL_DEPTH_TEST);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glDisable(GL_DEPTH_TEST);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SetTexFilter(void)
|
||
|
{
|
||
|
GLenum filter;
|
||
|
|
||
|
|
||
|
filter = linearFilter ? GL_LINEAR : GL_NEAREST;
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||
|
}
|
||
|
|
||
|
void ClearTex(void)
|
||
|
{
|
||
|
DDBLTFX ddbltfx;
|
||
|
RECT drct;
|
||
|
HRESULT hr;
|
||
|
|
||
|
drct.left = 0;
|
||
|
drct.top = 0;
|
||
|
drct.right = texWidth;
|
||
|
drct.bottom = texHeight;
|
||
|
|
||
|
memset(&ddbltfx, 0, sizeof(ddbltfx));
|
||
|
ddbltfx.dwSize = sizeof(ddbltfx);
|
||
|
ddbltfx.dwFillColor = 0;
|
||
|
|
||
|
hr = pddsTex->lpVtbl->Blt(pddsTex, &drct, NULL, NULL,
|
||
|
DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
|
||
|
if (hr != DD_OK)
|
||
|
{
|
||
|
Quit("Blt failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Key(UINT key)
|
||
|
{
|
||
|
switch(key)
|
||
|
{
|
||
|
case VK_ESCAPE:
|
||
|
Quit(NULL);
|
||
|
break;
|
||
|
|
||
|
case VK_SPACE:
|
||
|
spin = !spin;
|
||
|
break;
|
||
|
|
||
|
case 'D':
|
||
|
ToggleGl(GL_DITHER);
|
||
|
break;
|
||
|
|
||
|
case 'F':
|
||
|
linearFilter = !linearFilter;
|
||
|
SetTexFilter();
|
||
|
break;
|
||
|
|
||
|
case 'H':
|
||
|
stretch = !stretch;
|
||
|
break;
|
||
|
|
||
|
case 'M':
|
||
|
updateMovie = !updateMovie;
|
||
|
break;
|
||
|
|
||
|
case 'O':
|
||
|
if (++objIdx == NOBJS)
|
||
|
{
|
||
|
objIdx = 0;
|
||
|
}
|
||
|
SetObject(objIdx);
|
||
|
break;
|
||
|
|
||
|
case 'S':
|
||
|
spin = !spin;
|
||
|
break;
|
||
|
|
||
|
case 'T':
|
||
|
timings = !timings;
|
||
|
frames = 0;
|
||
|
ticks = 0;
|
||
|
break;
|
||
|
|
||
|
case 'X':
|
||
|
ToggleGl(GL_TEXTURE_2D);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL Message(GLDDWINDOW gw, HWND hwnd, UINT uiMsg, WPARAM wpm, LPARAM lpm,
|
||
|
LRESULT *plr)
|
||
|
{
|
||
|
switch(uiMsg)
|
||
|
{
|
||
|
case WM_KEYDOWN:
|
||
|
Key((UINT)wpm);
|
||
|
break;
|
||
|
|
||
|
case WM_SIZE:
|
||
|
winWidth = LOWORD(lpm);
|
||
|
winHeight = HIWORD(lpm);
|
||
|
SetView();
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*plr = 0;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void GetStreamFormat(void)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
LONG fmtSize;
|
||
|
void *pvFmt;
|
||
|
|
||
|
hr = AVIStreamFormatSize(aviStream, 0, &fmtSize);
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
Quit("AVIStreamFormatSize failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
|
||
|
pvFmt = malloc(fmtSize);
|
||
|
if (pvFmt == NULL)
|
||
|
{
|
||
|
Quit("Unable to allocate format buffer\n");
|
||
|
}
|
||
|
|
||
|
hr = AVIStreamReadFormat(aviStream, 0, pvFmt, &fmtSize);
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
Quit("AVIStreamReadFormat failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
|
||
|
UpdateBmi((BITMAPINFO *)pvFmt);
|
||
|
|
||
|
free(pvFmt);
|
||
|
}
|
||
|
|
||
|
void OpenMovie(void)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
AVISTREAMINFO sinfo;
|
||
|
BITMAPINFOHEADER *pbmih;
|
||
|
|
||
|
AVIFileInit();
|
||
|
|
||
|
hr = AVIStreamOpenFromFile(&aviStream, aviFileName, streamtypeVIDEO,
|
||
|
0, OF_READ | OF_SHARE_DENY_WRITE, NULL);
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
Quit("AVIStreamOpenFromFile failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
|
||
|
aviLength = AVIStreamLength(aviStream);
|
||
|
|
||
|
hr = AVIStreamInfo(aviStream, &sinfo, sizeof(sinfo));
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
Quit("AVIStreamInfo failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
|
||
|
if (sinfo.dwFlags & AVISTREAMINFO_FORMATCHANGES)
|
||
|
{
|
||
|
printf("WARNING: Stream contains format changes, unhandled\n");
|
||
|
}
|
||
|
|
||
|
GetStreamFormat();
|
||
|
|
||
|
movWidth = sinfo.rcFrame.right-sinfo.rcFrame.left;
|
||
|
movHeight = sinfo.rcFrame.bottom-sinfo.rcFrame.top;
|
||
|
|
||
|
#if 1
|
||
|
printf("Movie '%s' is %d x %d\n", aviFileName, movWidth, movHeight);
|
||
|
#endif
|
||
|
|
||
|
#if 0
|
||
|
if ((movWidth & (movWidth-1)) != 0 ||
|
||
|
(movHeight & (movHeight-1)) != 0)
|
||
|
{
|
||
|
Quit("Movie must have frames that are a power of two in size, "
|
||
|
"movie is %d x %d\n", movWidth, movHeight);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
pbmih = &pbmiMovie->bmiHeader;
|
||
|
memset(pbmih, 0, sizeof(BITMAPINFOHEADER));
|
||
|
pbmih->biSize = sizeof(BITMAPINFOHEADER);
|
||
|
pbmih->biWidth = movWidth;
|
||
|
pbmih->biHeight = movHeight;
|
||
|
pbmih->biPlanes = 1;
|
||
|
pbmih->biBitCount = 8;
|
||
|
pbmih->biCompression = BI_RGB;
|
||
|
|
||
|
aviGetFrame = AVIStreamGetFrameOpen(aviStream, pbmih);
|
||
|
if (aviGetFrame == NULL)
|
||
|
{
|
||
|
Quit("AVIStreamGetFrameOpen failed\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL WINAPI texCallback(LPDDSURFACEDESC pddsd, LPVOID pv)
|
||
|
{
|
||
|
if ((paletted && pddsd->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) ||
|
||
|
(!paletted && pddsd->ddpfPixelFormat.dwFlags == DDPF_RGB))
|
||
|
{
|
||
|
ddsdTex = *pddsd;
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CreateTex(int minWidth, int minHeight)
|
||
|
{
|
||
|
LPDIRECTDRAW pdd;
|
||
|
HRESULT hr;
|
||
|
|
||
|
texWidth = 1;
|
||
|
texHeight = 1;
|
||
|
while (texWidth < minWidth && texWidth < winWidth)
|
||
|
{
|
||
|
texWidth *= 2;
|
||
|
}
|
||
|
if (texWidth > winWidth)
|
||
|
{
|
||
|
texWidth /= 2;
|
||
|
}
|
||
|
while (texHeight < minHeight && texHeight < winHeight)
|
||
|
{
|
||
|
texHeight *= 2;
|
||
|
}
|
||
|
if (texHeight > winHeight)
|
||
|
{
|
||
|
texHeight /= 2;
|
||
|
}
|
||
|
|
||
|
if (!wglEnumTextureFormats(texCallback, NULL))
|
||
|
{
|
||
|
Quit("wglEnumTextureFormats failed, %d\n", GetLastError());
|
||
|
}
|
||
|
|
||
|
hr = DirectDrawCreate(NULL, &pdd, NULL);
|
||
|
if (hr != DD_OK)
|
||
|
{
|
||
|
Quit("DirectDrawCreate failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
hr = pdd->lpVtbl->SetCooperativeLevel(pdd, NULL, DDSCL_NORMAL);
|
||
|
if (hr != DD_OK)
|
||
|
{
|
||
|
Quit("SetCooperativeLevel failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
|
||
|
ddsdTex.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
|
||
|
ddsdTex.dwWidth = texWidth;
|
||
|
ddsdTex.dwHeight = texHeight;
|
||
|
ddsdTex.ddsCaps.dwCaps &= ~DDSCAPS_MIPMAP;
|
||
|
|
||
|
hr = pdd->lpVtbl->CreateSurface(pdd, &ddsdTex, &pddsTex, NULL);
|
||
|
if (hr != DD_OK)
|
||
|
{
|
||
|
Quit("Texture CreateSurface failed, 0x%08lX\n", hr);
|
||
|
}
|
||
|
|
||
|
ClearTex();
|
||
|
}
|
||
|
|
||
|
void Init(void)
|
||
|
{
|
||
|
HDC hdc, screen;
|
||
|
HFONT fnt;
|
||
|
|
||
|
pfnColorTableEXT = (PFNGLCOLORTABLEEXTPROC)
|
||
|
wglGetProcAddress("glColorTableEXT");
|
||
|
if (pfnColorTableEXT == NULL)
|
||
|
{
|
||
|
Quit("glColorTableEXT not supported\n");
|
||
|
}
|
||
|
pfnColorSubTableEXT = (PFNGLCOLORSUBTABLEEXTPROC)
|
||
|
wglGetProcAddress("glColorSubTableEXT");
|
||
|
if (pfnColorSubTableEXT == NULL)
|
||
|
{
|
||
|
Quit("glColorSubTableEXT not supported\n");
|
||
|
}
|
||
|
|
||
|
pbmiMovie = (BITMAPINFO *)malloc(sizeof(BITMAPINFO)+255*sizeof(RGBQUAD));
|
||
|
if (pbmiMovie == NULL)
|
||
|
{
|
||
|
Quit("Unable to allocate pbmiMovie\n");
|
||
|
}
|
||
|
|
||
|
OpenMovie();
|
||
|
|
||
|
// Must come after movie is open so width and height are set
|
||
|
CreateTex(movWidth, movHeight);
|
||
|
|
||
|
movX = (texWidth-movWidth)/2;
|
||
|
movY = (texHeight-movHeight)/2;
|
||
|
|
||
|
wglBindDirectDrawTexture(pddsTex);
|
||
|
|
||
|
// Create texture palette if necessary
|
||
|
if (paletted)
|
||
|
{
|
||
|
pfnColorTableEXT(GL_TEXTURE_2D, GL_RGB, 256, GL_BGRA_EXT,
|
||
|
GL_UNSIGNED_BYTE, pbmiMovie->bmiColors);
|
||
|
}
|
||
|
|
||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||
|
|
||
|
linearFilter = GL_FALSE;
|
||
|
SetTexFilter();
|
||
|
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
|
||
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||
|
|
||
|
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
||
|
|
||
|
// Fill in initial movie frame
|
||
|
curFrame = 0;
|
||
|
FrameToTex(curFrame);
|
||
|
|
||
|
// Provide letters for objects to compose themselves from
|
||
|
screen = GetDC(NULL);
|
||
|
hdc = CreateCompatibleDC(screen);
|
||
|
if (hdc == NULL)
|
||
|
{
|
||
|
Quit("CreateCompatibleDC failed, %d\n", GetLastError());
|
||
|
}
|
||
|
|
||
|
fnt = CreateFont(72, 0, 0, 0, FW_HEAVY, FALSE, FALSE, FALSE,
|
||
|
ANSI_CHARSET, OUT_TT_ONLY_PRECIS,
|
||
|
CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH |
|
||
|
TMPF_TRUETYPE | FF_DONTCARE, "Arial");
|
||
|
if (fnt == NULL)
|
||
|
{
|
||
|
Quit("CreateFont failed, %d\n", GetLastError());
|
||
|
}
|
||
|
|
||
|
SelectObject(hdc, fnt);
|
||
|
|
||
|
letters = glGenLists(NLETTERS);
|
||
|
|
||
|
if (!wglUseFontOutlines(hdc, FIRST_LETTER, NLETTERS, letters, 0.0f, 0.1f,
|
||
|
WGL_FONT_POLYGONS, letterMetrics))
|
||
|
{
|
||
|
Quit("wglUseFontOutlines failed, %d\n", GetLastError());
|
||
|
}
|
||
|
|
||
|
DeleteDC(hdc);
|
||
|
DeleteObject(fnt);
|
||
|
ReleaseDC(NULL, screen);
|
||
|
|
||
|
BuildLists();
|
||
|
|
||
|
SetObject(0);
|
||
|
|
||
|
xrot = 0.0;
|
||
|
yrot = 0.0;
|
||
|
|
||
|
SetView();
|
||
|
}
|
||
|
|
||
|
GLenum Args(int argc, char **argv)
|
||
|
{
|
||
|
GLint i;
|
||
|
|
||
|
winWidth = 320;
|
||
|
winHeight = 320;
|
||
|
doubleBuffer = GL_TRUE;
|
||
|
videoMemory = GL_FALSE;
|
||
|
noSwap = GL_FALSE;
|
||
|
noClear = GL_FALSE;
|
||
|
fullScreen = GL_FALSE;
|
||
|
fullWidth = 640;
|
||
|
fullHeight = 480;
|
||
|
fullDepth = 16;
|
||
|
useMcd = GL_FALSE;
|
||
|
modeX = GL_FALSE;
|
||
|
stretch = GL_TRUE;
|
||
|
paletted = GL_TRUE;
|
||
|
timings = GL_FALSE;
|
||
|
spin = GL_TRUE;
|
||
|
|
||
|
for (i = 1; i < argc; i++) {
|
||
|
if (strcmp(argv[i], "-sb") == 0) {
|
||
|
doubleBuffer = GL_FALSE;
|
||
|
} else if (strcmp(argv[i], "-db") == 0) {
|
||
|
doubleBuffer = GL_TRUE;
|
||
|
} else if (strcmp(argv[i], "-rgb") == 0) {
|
||
|
paletted = GL_FALSE;
|
||
|
} else if (strcmp(argv[i], "-stretch") == 0) {
|
||
|
stretch = GL_TRUE;
|
||
|
} else if (strcmp(argv[i], "-nostretch") == 0) {
|
||
|
stretch = GL_FALSE;
|
||
|
} else if (strcmp(argv[i], "-nospin") == 0) {
|
||
|
spin = GL_FALSE;
|
||
|
} else if (strcmp(argv[i], "-vm") == 0) {
|
||
|
videoMemory = GL_TRUE;
|
||
|
} else if (strcmp(argv[i], "-noswap") == 0) {
|
||
|
noSwap = GL_TRUE;
|
||
|
} else if (strcmp(argv[i], "-noclear") == 0) {
|
||
|
noClear = GL_TRUE;
|
||
|
} else if (strcmp(argv[i], "-full") == 0) {
|
||
|
fullScreen = GL_TRUE;
|
||
|
} else if (strcmp(argv[i], "-modex") == 0) {
|
||
|
modeX = GL_TRUE;
|
||
|
fullWidth = 320;
|
||
|
fullHeight = 240;
|
||
|
fullDepth = 8;
|
||
|
} else if (strcmp(argv[i], "-mcd") == 0) {
|
||
|
useMcd = GL_TRUE;
|
||
|
} else if (strcmp(argv[i], "-surf") == 0) {
|
||
|
if (i+2 >= argc ||
|
||
|
argv[i+1][0] == '-' ||
|
||
|
argv[i+2][0] == '-')
|
||
|
{
|
||
|
printf("-surf (No numbers).\n");
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
winWidth = atoi(argv[++i]);
|
||
|
winHeight = atoi(argv[++i]);
|
||
|
}
|
||
|
} else if (strcmp(argv[i], "-fdim") == 0) {
|
||
|
if (i+3 >= argc ||
|
||
|
argv[i+1][0] == '-' ||
|
||
|
argv[i+2][0] == '-' ||
|
||
|
argv[i+3][0] == '-')
|
||
|
{
|
||
|
printf("-fdim (No numbers).\n");
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fullWidth = atoi(argv[++i]);
|
||
|
fullHeight = atoi(argv[++i]);
|
||
|
fullDepth = atoi(argv[++i]);
|
||
|
}
|
||
|
} else if (strcmp(argv[i], "-mov") == 0) {
|
||
|
if (i+1 >= argc ||
|
||
|
argv[i+1][0] == '-')
|
||
|
{
|
||
|
printf("-mov (No filename).\n");
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
aviFileName = argv[++i];
|
||
|
}
|
||
|
} else {
|
||
|
printf("%s (Bad option).\n", argv[i]);
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
}
|
||
|
return GL_TRUE;
|
||
|
}
|
||
|
|
||
|
void __cdecl main(int argc, char **argv)
|
||
|
{
|
||
|
DWORD dwFlags;
|
||
|
GLDDWINDOW gw;
|
||
|
|
||
|
if (Args(argc, argv) == GL_FALSE) {
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
dwFlags = GLDD_Z_BUFFER_16;
|
||
|
dwFlags |= doubleBuffer ? GLDD_BACK_BUFFER : 0;
|
||
|
dwFlags |= videoMemory ? GLDD_VIDEO_MEMORY : 0;
|
||
|
dwFlags |= useMcd ? GLDD_GENERIC_ACCELERATED : 0;
|
||
|
if (fullScreen)
|
||
|
{
|
||
|
dwFlags |= GLDD_FULL_SCREEN;
|
||
|
dwFlags |= modeX ? GLDD_USE_MODE_X : 0;
|
||
|
winWidth = fullWidth;
|
||
|
winHeight = fullHeight;
|
||
|
}
|
||
|
|
||
|
gw = glddCreateWindow("Video Texture", 10, 30, winWidth, winHeight,
|
||
|
fullDepth, dwFlags);
|
||
|
if (gw == NULL)
|
||
|
{
|
||
|
printf("glddCreateWindow failed with 0x%08lX\n", glddGetLastError());
|
||
|
exit(1);
|
||
|
}
|
||
|
gwMain = gw;
|
||
|
|
||
|
glddMakeCurrent(gw);
|
||
|
|
||
|
Init();
|
||
|
|
||
|
glddIdleCallback(gw, Animate);
|
||
|
glddMessageCallback(gw, Message);
|
||
|
glddRun(gw);
|
||
|
|
||
|
Quit(NULL);
|
||
|
}
|