fteqw/engine/gl/gltod3d/gl_fakegl.cpp

4177 lines
111 KiB
C++

/*
Copyright (C) 2000 Jack Palevich.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// gl_fakegl.cpp -- Uses Direct3D 7.0 to implement a subset of OpenGL.
/*
This would probably be faster if it wasn't written in cpp.
the fact that it uses wrapper functions to call methods in a class could be a reasonable hit in speed.
*/
#include "bothdefs.h" //our always-present config file
#ifdef USE_D3D
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#if 0
#undef WINGDIAPI
#define WINGDIAPI
#undef APIENTRY
#define APIENTRY
#endif
#include <gl/gl.h>
#if 0
#undef APIENTRY
#define APIENTRY WINAPI
#undef WINGDIAPI
#define WINGDIAPI DECLSPEC_IMPORT
#endif
#pragma warning( disable : 4244 )
#pragma warning( disable : 4820 )
#if (_MSC_VER < 1400)
#define D3D_OVERLOADS
#endif
#define RELEASENULL(object) if (object) {object->Release();}
#include "ddraw.h"
#include "d3d.h"
#include "d3dx.h"
typedef HRESULT (WINAPI *qD3DXInitialize_t)();
qD3DXInitialize_t qD3DXInitialize;
typedef HRESULT (WINAPI *qD3DXUninitialize_t)();
qD3DXUninitialize_t qD3DXUninitialize;
typedef D3DXMATRIX* (WINAPI *qD3DXMatrixScaling_t) ( D3DXMATRIX *pOut, float sx, float sy, float sz );
qD3DXMatrixScaling_t qD3DXMatrixScaling;
typedef void (WINAPI *qD3DXGetErrorString_t)(HRESULT hr, DWORD strLength, LPSTR pStr);
qD3DXGetErrorString_t qD3DXGetErrorString;
typedef D3DXMATRIX* (WINAPI *qD3DXMatrixPerspectiveOffCenter_t) ( D3DXMATRIX *pOut, float l, float r, float b, float t, float zn, float zf );
qD3DXMatrixPerspectiveOffCenter_t qD3DXMatrixPerspectiveOffCenter;
typedef D3DXMATRIX* (WINAPI *qD3DXMatrixOrthoOffCenter_t) ( D3DXMATRIX *pOut, float l, float r, float b, float t, float zn, float zf );
qD3DXMatrixOrthoOffCenter_t qD3DXMatrixOrthoOffCenter;
typedef HRESULT (WINAPI *qD3DXCreateContextEx_t)(DWORD deviceIndex, DWORD flags,HWND hwnd,HWND hwndFocus, DWORD numColorBits,DWORD numAlphaBits,DWORD numDepthbits,DWORD numStencilBits,DWORD numBackBuffers,DWORD width, DWORD height,DWORD refreshRate,LPD3DXCONTEXT* ppCtx);
qD3DXCreateContextEx_t qD3DXCreateContextEx;
typedef HRESULT (WINAPI *qD3DXCreateMatrixStack_t)( DWORD flags, LPD3DXMATRIXSTACK *ppStack );
qD3DXCreateMatrixStack_t qD3DXCreateMatrixStack;
typedef HRESULT (WINAPI *qD3DXCheckTextureRequirements_t)( LPDIRECT3DDEVICE7 pd3dDevice, LPDWORD pFlags, LPDWORD pWidth, LPDWORD pHeight, D3DX_SURFACEFORMAT* pPixelFormat);
qD3DXCheckTextureRequirements_t qD3DXCheckTextureRequirements;
typedef HRESULT (WINAPI *qD3DXMakeDDPixelFormat_t) (D3DX_SURFACEFORMAT d3dxFormat, DDPIXELFORMAT* pddpf);
qD3DXMakeDDPixelFormat_t qD3DXMakeDDPixelFormat;
typedef D3DXMATRIX* (WINAPI *qD3DXMatrixTranslation_t) ( D3DXMATRIX *pOut, float x, float y, float z );
qD3DXMatrixTranslation_t qD3DXMatrixTranslation;
extern "C" {
#include "quakedef.h"
#include "glquake.h"
}
#ifdef USE_D3D
// Choose one of the following. D3DXContext is new in DX7, and
// provides a standard way of managing DX. D3DFrame is from
// the D3DIM sample code.
// Advantages of D3DXContext:
// + less code.
// + official standard.
// + Does standard things correctly. (For example I can get Gamma
// correction to work. I can't get it to work with D3DFrame,
// probably because I've left out some stupid step.)
//
// Advantages of D3DFrame
// + Some hacked DX7 drivers that are really DX6 drivers will crash
// with D3DXContext, but work with D3DFrame. Pre-release Windows 2000
// Voodoo drivers are an example.
// + Source is available, so you can do things any way you want.
#define USE_D3DXCONTEXT
// #define USE_D3DFRAME
#ifdef USE_D3DFRAME
#include "d3denum.h"
#include "d3dframe.h"
#include "d3dutil.h"
#endif
#if 0
#undef APIENTRY
#define APIENTRY
#endif
#define TEXTURE0_SGIS 0x835E
#define TEXTURE1_SGIS 0x835F
#ifdef _DEBUG
void LocalDebugBreak(){
DebugBreak();
}
#else
void LocalDebugBreak(){
}
#endif
// Globals
bool g_force16bitTextures;
bool gFullScreen = true;
DWORD gWidth = 640;
DWORD gHeight = 480;
DWORD gBpp = 16;
DWORD gZbpp = 16;
class FakeGL;
static FakeGL* gFakeGL;
class TextureEntry {
public:
TextureEntry(){
m_id = 0;
m_texture = 0;
m_format = D3DX_SF_UNKNOWN;
m_internalFormat = 0;
m_glTexParameter2DMinFilter = GL_NEAREST_MIPMAP_LINEAR;
m_glTexParameter2DMagFilter = GL_LINEAR;
m_glTexParameter2DWrapS = GL_REPEAT;
m_glTexParameter2DWrapT = GL_REPEAT;
m_maxAnisotropy = 1.0;
}
~TextureEntry(){
}
GLuint m_id;
LPDIRECTDRAWSURFACE7 m_texture;
D3DX_SURFACEFORMAT m_format;
GLint m_internalFormat;
GLint m_glTexParameter2DMinFilter;
GLint m_glTexParameter2DMagFilter;
GLint m_glTexParameter2DWrapS;
GLint m_glTexParameter2DWrapT;
float m_maxAnisotropy;
};
#define TASIZE 2000
class TextureTable {
public:
TextureTable(){
m_count = 0;
m_size = 0;
m_textures = 0;
m_currentTexture = 0;
m_currentID = 0;
BindTexture(0);
}
~TextureTable(){
DWORD i;
for(i = 0; i < m_count; i++) {
RELEASENULL(m_textures[i].m_texture);
}
for(i = 0; i < TASIZE; i++) {
RELEASENULL(m_textureArray[i].m_texture);
}
delete [] m_textures;
}
void BindTexture(GLuint id){
TextureEntry* oldEntry = m_currentTexture;
m_currentID = id;
if ( id < TASIZE ) {
m_currentTexture = m_textureArray + id;
if ( m_currentTexture->m_id ) {
return;
}
}
else {
// Check overflow table.
// Really ought to be a hash table.
for(DWORD i = 0; i < m_count; i++){
if ( id == m_textures[i].m_id ) {
m_currentTexture = m_textures + i;
return;
}
}
// It's a new ID.
// Ensure space in the table
if ( m_count >= m_size ) {
int newSize = m_size * 2 + 10;
TextureEntry* newTextures = new TextureEntry[newSize];
for(DWORD i = 0; i < m_count; i++ ) {
newTextures[i] = m_textures[i];
}
delete[] m_textures;
m_textures = newTextures;
m_size = newSize;
}
// Put new entry in table
oldEntry = m_currentTexture;
m_currentTexture = m_textures + m_count;
m_count++;
}
if ( oldEntry ) {
*m_currentTexture = *oldEntry;
}
m_currentTexture->m_id = id;
m_currentTexture->m_texture = NULL;
}
int GetCurrentID() {
return m_currentID;
}
TextureEntry* GetCurrentEntry() {
return m_currentTexture;
}
TextureEntry* GetEntry(GLuint id){
if ( m_currentID == id && m_currentTexture ) {
return m_currentTexture;
}
if ( id < TASIZE ) {
return &m_textureArray[id];
}
else {
// Check overflow table.
// Really ought to be a hash table.
for(DWORD i = 0; i < m_count; i++){
if ( id == m_textures[i].m_id ) {
return &m_textures[i];
}
}
}
return 0;
}
LPDIRECTDRAWSURFACE7 GetTexture(){
if ( m_currentTexture ) {
return m_currentTexture->m_texture;
}
return 0;
}
LPDIRECTDRAWSURFACE7 GetTexture(int id){
TextureEntry* entry = GetEntry(id);
if ( entry ) {
return entry->m_texture;
}
return 0;
}
D3DX_SURFACEFORMAT GetSurfaceFormat() {
if ( m_currentTexture ) {
return m_currentTexture->m_format;
}
return D3DX_SF_UNKNOWN;
}
GLint GetInternalFormat() {
if ( m_currentTexture ) {
return m_currentTexture->m_internalFormat;
}
return 0;
}
void SetTexture(LPDIRECTDRAWSURFACE7 texture, D3DX_SURFACEFORMAT d3dFormat, GLint internalFormat){
if ( !m_currentTexture ) {
BindTexture(0);
}
RELEASENULL ( m_currentTexture->m_texture );
m_currentTexture->m_texture = texture;
m_currentTexture->m_format = d3dFormat;
m_currentTexture->m_internalFormat = internalFormat;
}
private:
GLuint m_currentID;
DWORD m_count;
DWORD m_size;
TextureEntry m_textureArray[TASIZE]; // IDs 0..TASIZE-1
TextureEntry* m_textures; // Overflow
TextureEntry* m_currentTexture;
};
#if 1
#define Clamp(x) (x) // No clamping -- we've made sure the inputs are in the range 0..1
#else
float Clamp(float x) {
if ( x < 0 ) {
x = 0;
LocalDebugBreak();
}
else if ( x > 1 ) {
x = 1;
LocalDebugBreak();
}
return x;
}
#endif
static DWORD GLToDXSBlend(GLenum glBlend){
DWORD result = D3DBLEND_ONE;
switch ( glBlend ) {
case GL_ZERO: result = D3DBLEND_ZERO; break;
case GL_ONE: result = D3DBLEND_ONE; break;
case GL_DST_COLOR: result = D3DBLEND_DESTCOLOR; break;
case GL_ONE_MINUS_DST_COLOR: result = D3DBLEND_INVDESTCOLOR; break;
case GL_SRC_ALPHA: result = D3DBLEND_SRCALPHA; break;
case GL_ONE_MINUS_SRC_ALPHA: result = D3DBLEND_INVSRCALPHA; break;
case GL_DST_ALPHA: result = D3DBLEND_DESTALPHA; break;
case GL_ONE_MINUS_DST_ALPHA: result = D3DBLEND_INVDESTALPHA; break;
case GL_SRC_ALPHA_SATURATE: result = D3DBLEND_SRCALPHASAT; break;
default: LocalDebugBreak(); break;
}
return result;
}
static DWORD GLToDXDBlend(GLenum glBlend){
DWORD result = D3DBLEND_ONE;
switch ( glBlend ) {
case GL_ZERO: result = D3DBLEND_ZERO; break;
case GL_ONE: result = D3DBLEND_ONE; break;
case GL_SRC_COLOR: result = D3DBLEND_SRCCOLOR; break;
case GL_ONE_MINUS_SRC_COLOR: result = D3DBLEND_INVSRCCOLOR; break;
case GL_SRC_ALPHA: result = D3DBLEND_SRCALPHA; break;
case GL_ONE_MINUS_SRC_ALPHA: result = D3DBLEND_INVSRCALPHA; break;
case GL_DST_ALPHA: result = D3DBLEND_DESTALPHA; break;
case GL_ONE_MINUS_DST_ALPHA: result = D3DBLEND_INVDESTALPHA; break;
default: LocalDebugBreak(); break;
}
return result;
}
static DWORD GLToDXCompare(GLenum func){
DWORD result = D3DCMP_ALWAYS;
switch ( func ) {
case GL_NEVER: result = D3DCMP_NEVER; break;
case GL_LESS: result = D3DCMP_LESS; break;
case GL_EQUAL: result = D3DCMP_EQUAL; break;
case GL_LEQUAL: result = D3DCMP_LESSEQUAL; break;
case GL_GREATER: result = D3DCMP_GREATER; break;
case GL_NOTEQUAL: result = D3DCMP_NOTEQUAL; break;
case GL_GEQUAL: result = D3DCMP_GREATEREQUAL; break;
case GL_ALWAYS: result = D3DCMP_ALWAYS; break;
default: break;
}
return result;
}
/*
OpenGL MinFilter MipFilter Comments
GL_NEAREST D3DTFN_POINT D3DTFP_NONE
GL_LINEAR D3DTFN_LINEAR D3DTFP_NONE
GL_NEAREST_MIPMAP_NEAREST D3DTFN_POINT D3DTFP_POINT
GL_LINEAR_MIPMAP_NEAREST D3DTFN_LINEAR D3DTFP_POINT bilinear
GL_NEAREST_MIPMAP_LINEAR D3DTFN_POINT D3DTFP_LINEAR
GL_LINEAR_MIPMAP_LINEAR D3DTFN_LINEAR D3DTFP_LINEAR trilinear
*/
static DWORD GLToDXMinFilter(GLint filter){
DWORD result = D3DTFN_LINEAR;
switch ( filter ) {
case GL_NEAREST: result = D3DTFN_POINT; break;
case GL_LINEAR: result = D3DTFN_LINEAR; break;
case GL_NEAREST_MIPMAP_NEAREST: result = D3DTFN_POINT; break;
case GL_LINEAR_MIPMAP_NEAREST: result = D3DTFN_LINEAR; break;
case GL_NEAREST_MIPMAP_LINEAR: result = D3DTFN_POINT; break;
case GL_LINEAR_MIPMAP_LINEAR: result = D3DTFN_LINEAR; break;
default:
LocalDebugBreak();
break;
}
return result;
}
static DWORD GLToDXMipFilter(GLint filter){
DWORD result = D3DTFP_POINT;
switch ( filter ) {
case GL_NEAREST: result = D3DTFP_NONE; break;
case GL_LINEAR: result = D3DTFP_NONE; break;
case GL_NEAREST_MIPMAP_NEAREST: result = D3DTFP_POINT; break;
case GL_LINEAR_MIPMAP_NEAREST: result = D3DTFP_POINT; break;
case GL_NEAREST_MIPMAP_LINEAR: result = D3DTFP_LINEAR; break;
case GL_LINEAR_MIPMAP_LINEAR: result = D3DTFP_LINEAR; break;
default:
LocalDebugBreak();
break;
}
return result;
}
static DWORD GLToDXMagFilter(GLint filter){
DWORD result = D3DTFG_POINT;
switch ( filter ) {
case GL_NEAREST: result = D3DTFG_POINT; break;
case GL_LINEAR: result = D3DTFG_LINEAR; break;
default:
LocalDebugBreak();
break;
}
return result;
}
static DWORD GLToDXTextEnvMode(GLint mode){
DWORD result = D3DTOP_MODULATE;
switch ( mode ) {
case GL_MODULATE: result = D3DTOP_MODULATE; break;
case GL_DECAL: result = D3DTOP_SELECTARG1; break; // Fix this
case GL_BLEND: result = D3DTOP_BLENDTEXTUREALPHA; break;
case GL_REPLACE: result = D3DTOP_SELECTARG1; break;
default: break;
}
return result;
}
#define MAXSTATES 8
class TextureStageState {
public:
TextureStageState() {
m_currentTexture = 0;
m_glTextEnvMode = GL_MODULATE;
m_glTexture2D = false;
m_dirty = true;
}
bool GetDirty() { return m_dirty; }
void SetDirty(bool dirty) { m_dirty = dirty; }
void DirtyTexture(GLuint textureID) {
if ( textureID == m_currentTexture ) {
m_dirty = true;
}
}
GLuint GetCurrentTexture() { return m_currentTexture; }
void SetCurrentTexture(GLuint texture) { m_dirty = true; m_currentTexture = texture; }
GLfloat GetTextEnvMode() { return m_glTextEnvMode; }
void SetTextEnvMode(GLfloat mode) { m_dirty = true; m_glTextEnvMode = mode; }
bool GetTexture2D() { return m_glTexture2D; }
void SetTexture2D(bool texture2D) { m_dirty = true; m_glTexture2D = texture2D; }
private:
GLuint m_currentTexture;
GLfloat m_glTextEnvMode;
bool m_glTexture2D;
bool m_dirty;
};
class TextureState {
public:
TextureState(){
m_currentStage = 0;
memset(&m_stage, 0, sizeof(m_stage));
m_dirty = false;
m_mainBlend = false;
}
void SetMaxStages(int maxStages){
m_maxStages = maxStages;
for(int i = 0; i < m_maxStages;i++){
m_stage[i].SetDirty(true);
}
m_dirty = true;
}
// Keep track of changes to texture stage state
void SetCurrentStage(int index){
m_currentStage = index;
}
int GetMaxStages() { return m_maxStages; }
bool GetDirty() { return m_dirty; }
void DirtyTexture(int textureID){
for(int i = 0; i < m_maxStages;i++){
m_stage[i].DirtyTexture(textureID);
}
m_dirty = true;
}
void SetMainBlend(bool mainBlend){
m_mainBlend = mainBlend;
m_stage[0].SetDirty(true);
m_dirty = true;
}
// These methods apply to the current stage
GLuint GetCurrentTexture() { return Get()->GetCurrentTexture(); }
void SetCurrentTexture(GLuint texture) { m_dirty = true; Get()->SetCurrentTexture(texture); }
GLfloat GetTextEnvMode() { return Get()->GetTextEnvMode(); }
void SetTextEnvMode(GLfloat mode) { m_dirty = true; Get()->SetTextEnvMode(mode); }
bool GetTexture2D() { return Get()->GetTexture2D(); }
void SetTexture2D(bool texture2D) { m_dirty = true; Get()->SetTexture2D(texture2D); }
void SetTextureStageState(LPDIRECT3DDEVICE7 pD3DDev, TextureTable* textures){
if ( ! m_dirty ) {
return;
}
m_dirty = false;
for(int i = 0; i < m_maxStages; i++ ) {
if ( ! m_stage[i].GetDirty() ) {
continue;
}
m_stage[i].SetDirty(false);
if ( m_stage[i].GetTexture2D() ) {
DWORD color1 = D3DTA_TEXTURE;
int textEnvMode = m_stage[i].GetTextEnvMode();
DWORD colorOp = GLToDXTextEnvMode(textEnvMode);
if ( i > 0 && textEnvMode == GL_BLEND ) {
// Assume we're doing multi-texture light mapping.
// I don't think this is the right way to do this
// but it works for D3DQuake.
colorOp = D3DTOP_MODULATE;
color1 |= D3DTA_COMPLEMENT;
}
pD3DDev->SetTextureStageState( i, D3DTSS_COLORARG1, color1);
pD3DDev->SetTextureStageState( i, D3DTSS_COLORARG2, i == 0 ? D3DTA_DIFFUSE : D3DTA_CURRENT);
pD3DDev->SetTextureStageState( i, D3DTSS_COLOROP, colorOp);
DWORD alpha1 = D3DTA_TEXTURE;
DWORD alpha2 = D3DTA_DIFFUSE;
DWORD alphaOp;
alphaOp = GLToDXTextEnvMode(textEnvMode);
if (i == 0 && m_mainBlend ) {
alphaOp = D3DTOP_MODULATE; // Otherwise the console is never transparent
}
pD3DDev->SetTextureStageState( i, D3DTSS_ALPHAARG1, alpha1);
pD3DDev->SetTextureStageState( i, D3DTSS_ALPHAARG2, alpha2);
pD3DDev->SetTextureStageState( i, D3DTSS_ALPHAOP, alphaOp);
TextureEntry* entry = textures->GetEntry(m_stage[i].GetCurrentTexture());
if ( entry ) {
int minFilter = entry->m_glTexParameter2DMinFilter;
DWORD dxMinFilter = GLToDXMinFilter(minFilter);
DWORD dxMipFilter = GLToDXMipFilter(minFilter);
DWORD dxMagFilter = GLToDXMagFilter(entry->m_glTexParameter2DMagFilter);
// Avoid setting anisotropic if the user doesn't request it.
static bool bSetMaxAnisotropy = false;
if ( entry->m_maxAnisotropy != 1.0f ) {
bSetMaxAnisotropy = true;
if ( dxMagFilter == D3DTFG_LINEAR) {
dxMagFilter = D3DTFG_ANISOTROPIC;
}
if ( dxMinFilter == D3DTFN_LINEAR) {
dxMinFilter = D3DTFN_ANISOTROPIC;
}
}
if ( bSetMaxAnisotropy ) {
pD3DDev->SetTextureStageState( i, D3DTSS_MAXANISOTROPY, entry->m_maxAnisotropy);
}
pD3DDev->SetTextureStageState( i, D3DTSS_MINFILTER, dxMinFilter );
pD3DDev->SetTextureStageState( i, D3DTSS_MIPFILTER, dxMipFilter );
pD3DDev->SetTextureStageState( i, D3DTSS_MAGFILTER, dxMagFilter);
LPDIRECTDRAWSURFACE7 pTexture = entry->m_texture;
if ( pTexture ) {
pD3DDev->SetTexture( i, pTexture);
}
}
}
else {
pD3DDev->SetTexture( i, NULL);
pD3DDev->SetTextureStageState( i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pD3DDev->SetTextureStageState( i, D3DTSS_COLORARG2, i == 0 ? D3DTA_DIFFUSE : D3DTA_CURRENT);
pD3DDev->SetTextureStageState( i, D3DTSS_COLOROP, D3DTOP_DISABLE);
}
}
}
private:
TextureStageState* Get() {
return m_stage + m_currentStage;
}
bool m_dirty;
bool m_mainBlend;
int m_maxStages;
int m_currentStage;
TextureStageState m_stage[MAXSTATES];
};
// This class buffers up all the glVertex calls between
// glBegin and glEnd.
//
// Choose one of these three
// USE_DRAWINDEXEDPRIMITIVE seems slightly faster (54 fps vs 53 fps) than USE_DRAWPRIMITIVE.
// USE_DRAWINDEXEDPRIMITIVEVB is much slower (30fps vs 54fps), at least on GeForce Win9x 3.75.
// #define USE_DRAWPRIMITIVE
#define USE_DRAWINDEXEDPRIMITIVE
//#define USE_DRAWINDEXEDPRIMITIVEVB
#if defined(USE_DRAWINDEXEDPRIMITIVE) || defined(USE_DRAWINDEXEDPRIMITIVEVB)
#define USE_INDECIES
#endif
#ifdef USE_DRAWINDEXEDPRIMITIVEVB
// The DX 7 docs suggest that you can get away with just one
// vertex buffer. But drivers (NVIDIA 3.75 on Win2K) don't seem to like that.
#endif
#ifdef USE_INDECIES
#define VERTSUSED 1024
#define VERTSSLOP 100
#endif
#ifdef USE_INDECIES
class OGLPrimitiveVertexBuffer {
public:
OGLPrimitiveVertexBuffer(){
m_drawMode = (GLuint) -1;
m_size = 0;
m_count = 0;
m_OGLPrimitiveVertexBuffer = 0;
m_vertexCount = 0;
m_vertexTypeDesc = 0;
memset(m_textureCoords, 0, sizeof(m_textureCoords));
m_pD3DDev = 0;
#ifdef USE_DRAWINDEXEDPRIMITIVEVB
m_buffer = 0;
#else
m_buffer = 0;
#endif
m_color = (DWORD) D3DRGBA(0.0,0.0,0.0,1.0); // Don't know if this is correct
m_indecies = 0;
m_indexCount = 0;
}
~OGLPrimitiveVertexBuffer(){
delete [] m_indecies;
#ifdef USE_DRAWINDEXEDPRIMITIVEVB
RELEASENULL(m_buffer);
#else
delete[] m_buffer;
#endif
}
HRESULT Initialize(LPDIRECT3DDEVICE7 pD3DDev, IDirect3D7* pD3D7, bool hardwareTandL, DWORD typeDesc){
m_pD3DDev = pD3DDev;
int numVerts = VERTSUSED + VERTSSLOP;
m_vertexTypeDesc = typeDesc;
m_vertexSize = 0;
if ( m_vertexTypeDesc & D3DFVF_XYZ ) {
m_vertexSize += 3 * sizeof(float);
}
if ( m_vertexTypeDesc & D3DFVF_DIFFUSE ) {
m_vertexSize += 4;
}
int textureStages = (m_vertexTypeDesc & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
m_vertexSize += 2 * sizeof(float) * textureStages;
m_indexSize = numVerts * 3;
delete [] m_indecies;
m_indecies = new WORD[m_indexSize];
#ifdef USE_DRAWINDEXEDPRIMITIVEVB
D3DVERTEXBUFFERDESC vbdesc = {sizeof(D3DVERTEXBUFFERDESC)};
vbdesc.dwCaps = D3DVBCAPS_WRITEONLY;
if ( ! hardwareTandL ) {
vbdesc.dwCaps |= D3DVBCAPS_SYSTEMMEMORY;
}
vbdesc.dwFVF = typeDesc;
vbdesc.dwNumVertices = numVerts;
RELEASENULL(m_buffer);
HRESULT hr = pD3D7->CreateVertexBuffer(&vbdesc, &m_buffer, 0);
if ( FAILED(hr) ) {
return hr;
}
#else
m_size = (VERTSUSED + VERTSSLOP) * m_vertexSize;
delete[] m_buffer;
m_buffer = new char[m_size];
#endif
return S_OK;
}
DWORD GetVertexTypeDesc(){
return m_vertexTypeDesc;
}
LPVOID GetOGLPrimitiveVertexBuffer(){
return m_OGLPrimitiveVertexBuffer;
}
DWORD GetVertexCount(){
return m_vertexCount;
}
inline void SetColor(D3DCOLOR color){
m_color = color;
}
inline void SetTextureCoord0(float u, float v){
DWORD* pCoords = (DWORD*) m_textureCoords;
pCoords[0] = *(DWORD*)& u;
pCoords[1] = *(DWORD*)& v;
}
inline void SetTextureCoord(int textStage, float u, float v){
DWORD* pCoords = (DWORD*) m_textureCoords + (textStage << 1);
pCoords[0] = *(DWORD*)& u;
pCoords[1] = *(DWORD*)& v;
}
void CheckFlush() {
if ( m_size && m_indexCount &&
((m_count + m_vertexSize * VERTSSLOP > m_size )
|| (m_indexCount + VERTSSLOP*6 > m_indexSize) ) ) {
Flush();
}
}
void Flush() {
if ( m_indexCount > 0 ) {
#ifdef USE_DRAWINDEXEDPRIMITIVEVB
m_OGLPrimitiveVertexBuffer = 0;
m_buffer->Unlock();
HRESULT hr = m_pD3DDev->DrawIndexedPrimitiveVB(
D3DPT_TRIANGLELIST, m_buffer,
0, m_vertexCount, m_indecies, m_indexCount, 0);
if ( FAILED(hr) ) {
// LocalDebugBreak(); // ? NVidia driver sometimes says it's out of memory
}
#else
m_OGLPrimitiveVertexBuffer = 0;
HRESULT hr = m_pD3DDev->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST, m_vertexTypeDesc, m_buffer,
m_vertexCount, m_indecies, m_indexCount, 0);
if ( FAILED(hr) ) {
LocalDebugBreak(); // ? NVidia driver sometimes says it's out of memory
}
#endif
}
else {
LocalDebugBreak();
}
m_indexCount = 0;
m_vertexState = 0;
}
void SetVertex(float x, float y, float z){
bool bCheckFlush = false;
if (m_count + m_vertexSize > m_size) {
Ensure(m_vertexSize);
}
if ( ! m_OGLPrimitiveVertexBuffer ) {
LockBuffer();
}
DWORD* pFloat = (DWORD*) (m_OGLPrimitiveVertexBuffer + m_count);
pFloat[0] = *(DWORD*)& x;
pFloat[1] = *(DWORD*)& y;
pFloat[2] = *(DWORD*)& z;
const DWORD* pCoords = (DWORD*) m_textureCoords;
switch(m_vertexTypeDesc){
case (D3DFVF_XYZ | D3DFVF_DIFFUSE | (1 << D3DFVF_TEXCOUNT_SHIFT)):
pFloat[3] = m_color;
pFloat[4] = pCoords[0];
pFloat[5] = pCoords[1];
break;
case (D3DFVF_XYZ | D3DFVF_DIFFUSE | (2 << D3DFVF_TEXCOUNT_SHIFT)):
pFloat[3] = m_color;
pFloat[4] = pCoords[0];
pFloat[5] = pCoords[1];
pFloat[6] = pCoords[2];
pFloat[7] = pCoords[3];
break;
default:
{
if ( m_vertexTypeDesc & D3DFVF_DIFFUSE ) {
*pFloat++ = m_color;
}
int textureStages = (m_vertexTypeDesc & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
for ( int i = 0; i < textureStages; i++ ) {
*pFloat++ = *pCoords++;
*pFloat++ = *pCoords++;
}
}
break;
}
if( m_indexCount < m_indexSize - 5){
// Convert quads to double triangles
switch ( m_drawMode ) {
default:
LocalDebugBreak();
break;
case GL_LINES:
{
m_indecies[m_indexCount++] = m_vertexCount;
if ( m_vertexState++==1)
{
SetVertex(x+1, y+1, z+1);
// m_indecies[m_indexCount++] = m_vertexCount;
m_vertexState = 0;
bCheckFlush = true; // Flush for long sequences of quads.
}
}
break;
case GL_TRIANGLES:
m_indecies[m_indexCount++] = m_vertexCount;
if ( m_vertexState++ == 2 ) {
m_vertexState = 0;
bCheckFlush = true; // Flush for long sequences of triangles.
}
break;
case GL_QUADS:
{
if ( m_vertexState++ < 3) {
m_indecies[m_indexCount++] = m_vertexCount;
}
else {
// We've already done triangle (0 , 1, 2), now draw (2, 3, 0)
m_indecies[m_indexCount++] = m_vertexCount-1;
m_indecies[m_indexCount++] = m_vertexCount;
m_indecies[m_indexCount++] = m_vertexCount-3;
m_vertexState = 0;
bCheckFlush = true; // Flush for long sequences of quads.
}
}
break;
case GL_TRIANGLE_STRIP:
{
if ( m_vertexState > VERTSSLOP ) {
// This is a strip that's too big for us to buffer.
// (We can't just flush the buffer because we have to keep
// track of the last two vertices.
LocalDebugBreak();
}
if ( m_vertexState++ < 3) {
m_indecies[m_indexCount++] = m_vertexCount;
}
else {
// Flip triangles between clockwise and counter clockwise
if (m_vertexState & 1) {
// draw triangle [n-2 n-1 n]
m_indecies[m_indexCount++] = m_vertexCount-2;
m_indecies[m_indexCount++] = m_vertexCount-1;
m_indecies[m_indexCount++] = m_vertexCount;
}
else {
// draw triangle [n-1 n-2 n]
m_indecies[m_indexCount++] = m_vertexCount-1;
m_indecies[m_indexCount++] = m_vertexCount-2;
m_indecies[m_indexCount++] = m_vertexCount;
}
}
}
break;
case GL_TRIANGLE_FAN:
case GL_POLYGON:
{
if ( m_vertexState > VERTSSLOP ) {
// This is a polygon or fan that's too big for us to buffer.
// (We can't just flush the buffer because we have to keep
// track of the starting vertex.
LocalDebugBreak();
}
if ( m_vertexState++ < 3) {
m_indecies[m_indexCount++] = m_vertexCount;
}
else {
// Draw triangle [0 n-1 n]
m_indecies[m_indexCount++] = m_vertexCount-(m_vertexState-1);
m_indecies[m_indexCount++] = m_vertexCount-1;
m_indecies[m_indexCount++] = m_vertexCount;
}
}
break;
}
}
else {
LocalDebugBreak();
}
m_count += m_vertexSize;
m_vertexCount++;
if ( bCheckFlush ) {
CheckFlush();
}
}
inline bool IsMergableMode(GLenum /* mode */){
CheckFlush();
return true;
}
void Begin(GLuint drawMode){
m_drawMode = drawMode;
CheckFlush();
if ( ! m_OGLPrimitiveVertexBuffer ) {
LockBuffer();
}
m_vertexState = 0;
}
void Append(GLuint drawMode){
m_drawMode = drawMode;
CheckFlush();
m_vertexState = 0;
}
void LockBuffer(){
if ( ! m_OGLPrimitiveVertexBuffer ) {
#ifdef USE_DRAWINDEXEDPRIMITIVEVB
void* memory = 0;
// If there's room in the buffer, we try to append to what's already there.
DWORD dwFlags = DDLOCK_WAIT | DDLOCK_WRITEONLY;
if ( m_vertexCount > 0 && m_vertexCount < VERTSUSED ){
dwFlags |= DDLOCK_NOOVERWRITE;
}
else {
m_vertexCount = 0;
m_count = 0;
dwFlags |= DDLOCK_DISCARDCONTENTS;
}
HRESULT hr = m_buffer->Lock(dwFlags, & memory, &m_size);
if ( FAILED(hr) || ! memory) {
// LocalDebugBreak();
while (!memory)
hr = m_buffer->Lock(dwFlags, & memory, &m_size);
}
m_OGLPrimitiveVertexBuffer = (char*) memory;
#else
m_OGLPrimitiveVertexBuffer = (char*) m_buffer;
m_vertexCount = 0;
m_count = 0;
#endif
m_indexCount = 0;
}
}
void End(){
if ( m_indexCount == 0 ) { // Startup
return;
}
Flush();
}
private:
void Ensure(int size){
if (( m_count + size ) > m_size ) {
LocalDebugBreak();
}
}
GLuint m_drawMode;
DWORD m_vertexTypeDesc;
int m_vertexSize; // in bytes
LPDIRECT3DDEVICE7 m_pD3DDev;
#ifdef USE_DRAWINDEXEDPRIMITIVEVB
IDirect3DVertexBuffer7* m_buffer;
#else
char* m_buffer;
#endif
char* m_OGLPrimitiveVertexBuffer;
DWORD m_size; // total vertex buffer size in bytes
DWORD m_count; // used ammount of vertex buffer, in bytes
DWORD m_vertexCount;
DWORD m_indexCount;
int m_vertexState; // Cycles from 0..n-1 where n is the number of verticies in a primitive.
DWORD m_indexSize;
WORD* m_indecies;
D3DCOLOR m_color;
float m_textureCoords[MAXSTATES*2];
};
#endif
#ifdef USE_DRAWPRIMITIVE
class OGLPrimitiveVertexBuffer {
public:
OGLPrimitiveVertexBuffer(){
m_drawMode = -1;
m_size = 0;
m_count = 0;
m_OGLPrimitiveVertexBuffer = 0;
m_vertexCount = 0;
m_vertexTypeDesc = 0;
memset(m_textureCoords, 0, sizeof(m_textureCoords));
m_pD3DDev = 0;
m_color = D3DRGBA(0.0,0.0,0.0,1.0); // Don't know if this is correct
}
~OGLPrimitiveVertexBuffer(){
delete [] m_OGLPrimitiveVertexBuffer;
}
HRESULT Initialize(LPDIRECT3DDEVICE7 pD3DDev, IDirect3D7* pD3D7, bool hardwareTandL, DWORD typeDesc){
m_pD3DDev = pD3DDev;
if (m_vertexTypeDesc != typeDesc) {
m_vertexTypeDesc = typeDesc;
m_vertexSize = 0;
if ( m_vertexTypeDesc & D3DFVF_XYZ ) {
m_vertexSize += 3 * sizeof(float);
}
if ( m_vertexTypeDesc & D3DFVF_DIFFUSE ) {
m_vertexSize += 4;
}
int textureStages = (m_vertexTypeDesc & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
m_vertexSize += 2 * sizeof(float) * textureStages;
}
return S_OK;
}
DWORD GetVertexTypeDesc(){
return m_vertexTypeDesc;
}
LPVOID GetOGLPrimitiveVertexBuffer(){
return m_OGLPrimitiveVertexBuffer;
}
DWORD GetVertexCount(){
return m_vertexCount;
}
inline void SetColor(D3DCOLOR color){
m_color = color;
}
inline void SetTextureCoord0(float u, float v){
DWORD* pCoords = (DWORD*) m_textureCoords;
pCoords[0] = *(DWORD*)& u;
pCoords[1] = *(DWORD*)& v;
}
inline void SetTextureCoord(int textStage, float u, float v){
DWORD* pCoords = (DWORD*) m_textureCoords + (textStage << 1);
pCoords[0] = *(DWORD*)& u;
pCoords[1] = *(DWORD*)& v;
}
void SetVertex(float x, float y, float z){
int newCount = m_count + m_vertexSize;
if (newCount > m_size) {
Ensure(m_vertexSize);
}
DWORD* pFloat = (DWORD*) (m_OGLPrimitiveVertexBuffer + m_count);
pFloat[0] = *(DWORD*)& x;
pFloat[1] = *(DWORD*)& y;
pFloat[2] = *(DWORD*)& z;
const DWORD* pCoords = (DWORD*) m_textureCoords;
switch(m_vertexTypeDesc){
case (D3DFVF_XYZ | D3DFVF_DIFFUSE | (1 << D3DFVF_TEXCOUNT_SHIFT)):
pFloat[3] = m_color;
pFloat[4] = pCoords[0];
pFloat[5] = pCoords[1];
break;
case (D3DFVF_XYZ | D3DFVF_DIFFUSE | (2 << D3DFVF_TEXCOUNT_SHIFT)):
pFloat[3] = m_color;
pFloat[4] = pCoords[0];
pFloat[5] = pCoords[1];
pFloat[6] = pCoords[2];
pFloat[7] = pCoords[3];
break;
default:
{
if ( m_vertexTypeDesc & D3DFVF_DIFFUSE ) {
*pFloat++ = m_color;
}
int textureStages = (m_vertexTypeDesc & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
for ( int i = 0; i < textureStages; i++ ) {
*pFloat++ = *pCoords++;
*pFloat++ = *pCoords++;
}
}
break;
}
m_count = newCount;
m_vertexCount++;
// TO DO: Flush vertex buffer if larger than 1000 vertexes.
// Have to do this modulo vertexes-per-primitive
}
inline IsMergableMode(GLenum mode){
return ( mode == m_drawMode ) && ( mode == GL_QUADS || mode == GL_TRIANGLES );
}
void Begin(GLuint drawMode){
m_drawMode = drawMode;
}
void Append(GLuint drawMode){
}
void End(){
if ( m_vertexCount == 0 ) { // Startup
return;
}
D3DPRIMITIVETYPE dptPrimitiveType;
switch ( m_drawMode ) {
case GL_POINTS: dptPrimitiveType = D3DPT_POINTLIST; break;
case GL_LINES: dptPrimitiveType = D3DPT_LINELIST; break;
case GL_LINE_STRIP: dptPrimitiveType = D3DPT_LINESTRIP; break;
case GL_LINE_LOOP:
dptPrimitiveType = D3DPT_LINESTRIP;
LocalDebugBreak(); // Need to add one more point
break;
case GL_TRIANGLES: dptPrimitiveType = D3DPT_TRIANGLELIST; break;
case GL_TRIANGLE_STRIP: dptPrimitiveType = D3DPT_TRIANGLESTRIP; break;
case GL_TRIANGLE_FAN: dptPrimitiveType = D3DPT_TRIANGLEFAN; break;
case GL_QUADS:
if ( m_vertexCount <= 4 ) {
dptPrimitiveType = D3DPT_TRIANGLEFAN;
}
else {
dptPrimitiveType = D3DPT_TRIANGLELIST;
ConvertQuadsToTriangles();
}
break;
case GL_QUAD_STRIP:
if ( m_vertexCount <= 4 ) {
dptPrimitiveType = D3DPT_TRIANGLEFAN;
}
else {
dptPrimitiveType = D3DPT_TRIANGLESTRIP;
ConvertQuadStripToTriangleStrip();
}
break;
case GL_POLYGON:
dptPrimitiveType = D3DPT_TRIANGLEFAN;
if ( m_vertexCount < 3) {
goto exit;
}
// How is this different from GL_TRIANGLE_FAN, other than
// that polygons are planar?
break;
default:
LocalDebugBreak();
goto exit;
}
{
HRESULT hr = m_pD3DDev->DrawPrimitive(
dptPrimitiveType, m_vertexTypeDesc,
m_OGLPrimitiveVertexBuffer,
m_vertexCount, 0);
if ( FAILED(hr) ) {
// LocalDebugBreak();
}
}
exit:
m_vertexCount = 0;
m_count = 0;
}
private:
void ConvertQuadsToTriangles(){
int quadCount = m_vertexCount / 4;
int addedVerticies = 2 * quadCount;
int addedDataSize = addedVerticies * m_vertexSize;
Ensure( addedDataSize );
// A quad is v0, v1, v2, v3
// The corresponding triangle pair is v0 v1 v2 , v0 v2 v3
for(int i = quadCount-1; i >= 0; i--) {
int startOfQuad = i * m_vertexSize * 4;
int startOfTrianglePair = i * m_vertexSize * 6;
// Copy the last two verticies of the second triangle
memcpy(m_OGLPrimitiveVertexBuffer + startOfTrianglePair + 4 * m_vertexSize,
m_OGLPrimitiveVertexBuffer + startOfQuad + m_vertexSize * 2, m_vertexSize * 2);
// Copy the first vertex of the second triangle
memcpy(m_OGLPrimitiveVertexBuffer + startOfTrianglePair + 3 * m_vertexSize,
m_OGLPrimitiveVertexBuffer + startOfQuad, m_vertexSize);
// Copy the first triangle
if ( i > 0 ) {
memcpy(m_OGLPrimitiveVertexBuffer + startOfTrianglePair, m_OGLPrimitiveVertexBuffer + startOfQuad, 3 * m_vertexSize);
}
}
m_count += addedDataSize;
m_vertexCount += addedVerticies;
}
void ConvertQuadStripToTriangleStrip(){
int vertexPairCount = m_vertexCount / 2;
// Doesn't add any points, but does reorder the verticies.
// Swap each pair of verticies.
for(int i = 0; i < vertexPairCount; i++) {
int startOfPair = i * m_vertexSize * 2;
int middleOfPair = startOfPair + m_vertexSize;
for(int j = 0; j < m_vertexSize; j++) {
int c = m_OGLPrimitiveVertexBuffer[startOfPair + j];
m_OGLPrimitiveVertexBuffer[startOfPair + j] = m_OGLPrimitiveVertexBuffer[middleOfPair + j];
m_OGLPrimitiveVertexBuffer[middleOfPair + j] = c;
}
}
}
void Ensure(int size){
if (( m_count + size ) > m_size ) {
int newSize = m_size * 2;
if ( newSize < m_count + size ) newSize = m_count + size;
char* newVB = new char[newSize];
if ( m_OGLPrimitiveVertexBuffer ) {
memcpy(newVB, m_OGLPrimitiveVertexBuffer, m_count);
}
delete[] m_OGLPrimitiveVertexBuffer;
m_OGLPrimitiveVertexBuffer = newVB;
m_size = newSize;
}
}
GLuint m_drawMode;
DWORD m_vertexTypeDesc;
int m_vertexSize; // in bytes
LPDIRECT3DDEVICE7 m_pD3DDev;
char* m_OGLPrimitiveVertexBuffer;
int m_size;
int m_count;
DWORD m_vertexCount;
D3DCOLOR m_color;
float m_textureCoords[MAXSTATES*2];
};
#endif // USE_DRAWPRIMITIVE
class FakeGL {
private:
LPDIRECT3DDEVICE7 m_pD3DDev;
LPDIRECTDRAW7 m_pDD;
LPDIRECT3D7 m_pD3D;
LPDIRECTDRAWSURFACE7 m_pPrimary;
#ifdef USE_D3DXCONTEXT
ID3DXContext* m_pD3DX;
#endif
bool m_hardwareTandL;
BOOL m_bD3DXReady;
HWND m_hwndMain;
bool m_glRenderStateDirty;
bool m_glAlphaStateDirty;
GLenum m_glAlphaFunc;
GLclampf m_glAlphaFuncRef;
bool m_glAlphaTest;
bool m_glBlendStateDirty;
bool m_glBlend;
GLenum m_glBlendFuncSFactor;
GLenum m_glBlendFuncDFactor;
bool m_glCullStateDirty;
bool m_glCullFace;
GLenum m_glCullFaceMode;
bool m_glDepthStateDirty;
bool m_glDepthTest;
GLenum m_glDepthFunc;
bool m_glDepthMask;
GLclampd m_glDepthRangeNear;
GLclampd m_glDepthRangeFar;
GLenum m_glMatrixMode;
GLenum m_glPolygonModeFront;
GLenum m_glPolygonModeBack;
bool m_glShadeModelStateDirty;
GLenum m_glShadeModel;
bool m_bViewPortDirty;
GLint m_glViewPortX;
GLint m_glViewPortY;
GLsizei m_glViewPortWidth;
GLsizei m_glViewPortHeight;
TextureState m_textureState;
TextureTable m_textures;
bool m_modelViewMatrixStateDirty;
bool m_projectionMatrixStateDirty;
bool m_textureMatrixStateDirty;
bool* m_currentMatrixStateDirty; // an alias to one of the preceeding stacks
ID3DXMatrixStack* m_modelViewMatrixStack;
ID3DXMatrixStack* m_projectionMatrixStack;
ID3DXMatrixStack* m_textureMatrixStack;
ID3DXMatrixStack* m_currentMatrixStack; // an alias to one of the preceeding stacks
bool m_viewMatrixStateDirty;
D3DXMATRIX m_d3dViewMatrix;
OGLPrimitiveVertexBuffer m_OGLPrimitiveVertexBuffer;
bool m_needBeginScene;
const char* m_vendor;
const char* m_renderer;
char m_version[64];
const char* m_extensions;
DDDEVICEIDENTIFIER2 m_dddi;
DWORD m_windowHeight;
char* m_stickyAlloc;
DWORD m_stickyAllocSize;
bool m_hintGenerateMipMaps;
#ifdef USE_D3DFRAME
D3DCOLOR m_clearColor;
#endif
HRESULT ReleaseD3DX()
{
#ifdef USE_D3DFRAME
Cleanup3DEnvironment();
#endif
#ifdef USE_D3DXCONTEXT
RELEASENULL(m_pDD);
RELEASENULL(m_pD3D);
RELEASENULL(m_pD3DDev);
RELEASENULL(m_pPrimary);
RELEASENULL(m_pD3DX);
#endif
m_bD3DXReady = FALSE;
qD3DXUninitialize();
return S_OK;
}
#ifdef USE_D3DFRAME
static HRESULT AppConfirmFn(DDCAPS* caps, D3DDEVICEDESC7* desc){
return S_OK;
}
#endif
HRESULT InitD3DX()
{
HRESULT hr;
if( FAILED(hr = qD3DXInitialize()) )
return hr;
#ifdef USE_D3DFRAME
// Choose device
hr = D3DEnum_EnumerateDevices(&AppConfirmFn);
if( FAILED(hr) )
return hr;
hr = D3DEnum_SelectDefaultDevice(&m_pDeviceInfo, 0);
if( FAILED(hr) )
return hr;
m_pDeviceInfo->bWindowed = gFullScreen ? 0 : 1;
m_pFramework = new CD3DFramework7();
if( FAILED( hr = Initialize3DEnvironment() ) )
return hr;
#endif
#ifdef USE_D3DXCONTEXT
DWORD width = gWidth;
DWORD height = gHeight;
DWORD bpp = gBpp;
DWORD zbpp = gZbpp;
// Try as specified.
hr = qD3DXCreateContextEx(D3DX_DEFAULT, gFullScreen ? D3DX_CONTEXT_FULLSCREEN : 0,
m_hwndMain, NULL, bpp, 0,
zbpp, 0, 1, width, height, D3DX_DEFAULT, &m_pD3DX);
if( FAILED(hr) ) {
// default z-buffer
hr = qD3DXCreateContextEx(D3DX_DEFAULT, gFullScreen ? D3DX_CONTEXT_FULLSCREEN : 0,
m_hwndMain, NULL, bpp, 0,
D3DX_DEFAULT, 0, 1, width, height, D3DX_DEFAULT, &m_pD3DX);
if( FAILED(hr) ) {
// default depth and z-buffer
hr = qD3DXCreateContextEx(D3DX_DEFAULT, gFullScreen ? D3DX_CONTEXT_FULLSCREEN : 0,
m_hwndMain, NULL, D3DX_DEFAULT, 0,
D3DX_DEFAULT, 0, 1, width, height, D3DX_DEFAULT, &m_pD3DX);
if( FAILED(hr) ) {
// default everything
hr = qD3DXCreateContextEx(D3DX_DEFAULT, gFullScreen ? D3DX_CONTEXT_FULLSCREEN : 0,
m_hwndMain, NULL, D3DX_DEFAULT, 0,
D3DX_DEFAULT, 0, 1, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, &m_pD3DX);
if( FAILED(hr) ) {
return hr;
}
}
}
}
m_pDD = m_pD3DX->GetDD();
m_pD3D = m_pD3DX->GetD3D();
m_pD3DDev = m_pD3DX->GetD3DDevice();
m_pPrimary = m_pD3DX->GetPrimary();
#endif
m_bD3DXReady = TRUE;
return hr;
}
void InterpretError(HRESULT hr)
{
char errStr[100];
qD3DXGetErrorString(hr, 100, errStr );
Con_Printf("%s\n", errStr);
// MessageBox(NULL,errStr,"D3DX Error",MB_OK);
// LocalDebugBreak();
}
#ifdef USE_D3DFRAME
D3DEnum_DeviceInfo* m_pDeviceInfo;
LPDIRECTDRAWSURFACE7 m_pddsRenderTargetLeft;
DDSURFACEDESC2 m_ddsdRenderTarget;
CD3DFramework7* m_pFramework;
//-----------------------------------------------------------------------------
// Name: Initialize3DEnvironment()
// Desc: Initializes the sample framework, then calls the app-specific function
// to initialize device specific objects. This code is structured to
// handled any errors that may occur duing initialization
//-----------------------------------------------------------------------------
HRESULT Initialize3DEnvironment()
{
HRESULT hr;
DWORD dwFrameworkFlags = 0L;
dwFrameworkFlags |= ( !m_pDeviceInfo->bWindowed ? D3DFW_FULLSCREEN : 0L );
dwFrameworkFlags |= ( m_pDeviceInfo->bStereo ? D3DFW_STEREO : 0L );
dwFrameworkFlags |= ( D3DFW_ZBUFFER );
// Initialize the D3D framework
if( SUCCEEDED( hr = m_pFramework->Initialize( m_hwndMain,
m_pDeviceInfo->pDriverGUID, m_pDeviceInfo->pDeviceGUID,
&m_pDeviceInfo->ddsdFullscreenMode, dwFrameworkFlags ) ) )
{
m_pDD = m_pFramework->GetDirectDraw();
m_pD3D = m_pFramework->GetDirect3D();
m_pD3DDev = m_pFramework->GetD3DDevice();
m_pPrimary = m_pFramework->GetRenderSurface();
m_pddsRenderTargetLeft = m_pFramework->GetRenderSurfaceLeft();
m_ddsdRenderTarget.dwSize = sizeof(m_ddsdRenderTarget);
m_pPrimary->GetSurfaceDesc( &m_ddsdRenderTarget );
// Let the app run its startup code which creates the 3d scene.
if( SUCCEEDED( hr = InitDeviceObjects() ) )
return S_OK;
else
{
DeleteDeviceObjects();
m_pFramework->DestroyObjects();
}
}
// If we get here, the first initialization passed failed. If that was with a
// hardware device, try again using a software rasterizer instead.
if( m_pDeviceInfo->bHardware )
{
// Try again with a software rasterizer
// DisplayFrameworkError( hr, MSGWARN_SWITCHEDTOSOFTWARE );
D3DEnum_SelectDefaultDevice( &m_pDeviceInfo, D3DENUM_SOFTWAREONLY );
return Initialize3DEnvironment();
}
return hr;
}
//-----------------------------------------------------------------------------
// Name: Change3DEnvironment()
// Desc: Handles driver, device, and/or mode changes for the app.
//-----------------------------------------------------------------------------
HRESULT Change3DEnvironment()
{
HRESULT hr;
static BOOL bOldWindowedState = TRUE;
static DWORD dwSavedStyle;
static RECT rcSaved;
// Release all scene objects that will be re-created for the new device
DeleteDeviceObjects();
// Release framework objects, so a new device can be created
if( FAILED( hr = m_pFramework->DestroyObjects() ) )
{
// DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
SendMessage( m_hwndMain, WM_CLOSE, 0, 0 );
return hr;
}
// Check if going from fullscreen to windowed mode, or vice versa.
if( bOldWindowedState != m_pDeviceInfo->bWindowed )
{
if( m_pDeviceInfo->bWindowed )
{
// Coming from fullscreen mode, so restore window properties
SetWindowLong( m_hwndMain, GWL_STYLE, dwSavedStyle );
SetWindowPos( m_hwndMain, HWND_NOTOPMOST, rcSaved.left, rcSaved.top,
( rcSaved.right - rcSaved.left ),
( rcSaved.bottom - rcSaved.top ), SWP_SHOWWINDOW );
}
else
{
// Going to fullscreen mode, save/set window properties as needed
dwSavedStyle = GetWindowLong( m_hwndMain, GWL_STYLE );
GetWindowRect( m_hwndMain, &rcSaved );
SetWindowLong( m_hwndMain, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
}
bOldWindowedState = m_pDeviceInfo->bWindowed;
}
// Inform the framework class of the driver change. It will internally
// re-create valid surfaces, a d3ddevice, etc.
if( FAILED( hr = Initialize3DEnvironment() ) )
{
// DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
SendMessage( m_hwndMain, WM_CLOSE, 0, 0 );
return hr;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Render3DEnvironment()
// Desc: Draws the scene.
//-----------------------------------------------------------------------------
HRESULT Render3DEnvironment()
{
HRESULT hr;
// Check the cooperative level before rendering
if( FAILED( hr = m_pDD->TestCooperativeLevel() ) )
{
switch( hr )
{
case DDERR_EXCLUSIVEMODEALREADYSET:
case DDERR_NOEXCLUSIVEMODE:
// Do nothing because some other app has exclusive mode
return S_OK;
case DDERR_WRONGMODE:
// The display mode changed on us. Resize accordingly
if( m_pDeviceInfo->bWindowed )
return Change3DEnvironment();
break;
}
return hr;
}
// Show the frame on the primary surface.
if( FAILED( hr = m_pFramework->ShowFrame() ) )
{
if( DDERR_SURFACELOST != hr )
return hr;
m_pFramework->RestoreSurfaces();
RestoreSurfaces();
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Cleanup3DEnvironment()
// Desc: Cleanup scene objects
//-----------------------------------------------------------------------------
void Cleanup3DEnvironment()
{
if( m_pFramework )
{
DeleteDeviceObjects();
delete m_pFramework; m_pFramework = 0;
FinalCleanup();
}
D3DEnum_FreeResources();
}
// Overridable functions for the 3D scene created by the app
virtual HRESULT OneTimeSceneInit() { return S_OK; }
virtual HRESULT InitDeviceObjects() { return S_OK; }
virtual HRESULT DeleteDeviceObjects() { return S_OK; }
virtual HRESULT Render() { return S_OK; }
virtual HRESULT FrameMove( FLOAT ) { return S_OK; }
virtual HRESULT RestoreSurfaces() { return S_OK; }
virtual HRESULT FinalCleanup() { return S_OK; }
#endif
public:
FakeGL(HWND hwndMain){
m_hwndMain = hwndMain;
RECT rect;
GetClientRect(m_hwndMain, &rect);
m_windowHeight = rect.bottom - rect.top;
m_bD3DXReady = TRUE;
m_pD3DDev = 0;
m_pDD = 0;
m_pD3D = 0;
m_pPrimary = 0;
#ifdef USE_D3DXCONTEXT
m_pD3DX = 0;
#endif
#ifdef USE_D3DFRAME
m_clearColor = 0;
#endif
m_hardwareTandL = false;
m_glRenderStateDirty = true;
m_glAlphaStateDirty = true;
m_glAlphaFunc = GL_ALWAYS;
m_glAlphaFuncRef = 0;
m_glAlphaTest = false;
m_glBlendStateDirty = true;
m_glBlend = false;
m_glBlendFuncSFactor = GL_ONE; // Not sure this is the default
m_glBlendFuncDFactor = GL_ZERO; // Not sure this is the default
m_glCullStateDirty = true;
m_glCullFace = false;
m_glCullFaceMode = GL_BACK;
m_glDepthStateDirty = true;
m_glDepthTest = false;
m_glDepthMask = true;
m_glDepthFunc = GL_ALWAYS; // not sure if this is the default
m_glDepthRangeNear = 0; // not sure if this is the default
m_glDepthRangeFar = 1.0; // not sure if this is the default
m_glMatrixMode = GL_MODELVIEW; // Not sure this is the default
m_glPolygonModeFront = GL_FILL;
m_glPolygonModeBack = GL_FILL;
m_glShadeModelStateDirty = true;
m_glShadeModel = GL_SMOOTH;
m_bViewPortDirty = true;
m_glViewPortX = 0;
m_glViewPortY = 0;
m_glViewPortWidth = rect.right - rect.left;
m_glViewPortHeight = rect.bottom - rect.top;
m_vendor = 0;
m_renderer = 0;
m_extensions = 0;
m_hintGenerateMipMaps = true;
HRESULT hr = InitD3DX();
if ( FAILED(hr) ) {
InterpretError(hr);
}
hr = qD3DXCreateMatrixStack(0, &m_modelViewMatrixStack);
hr = qD3DXCreateMatrixStack(0, &m_projectionMatrixStack);
hr = qD3DXCreateMatrixStack(0, &m_textureMatrixStack);
m_currentMatrixStack = m_modelViewMatrixStack;
m_modelViewMatrixStack->LoadIdentity(); // Not sure this is correct
m_projectionMatrixStack->LoadIdentity();
m_textureMatrixStack->LoadIdentity();
m_modelViewMatrixStateDirty = true;
m_projectionMatrixStateDirty = true;
m_textureMatrixStateDirty = true;
m_currentMatrixStateDirty = &m_modelViewMatrixStateDirty;
m_viewMatrixStateDirty = true;
D3DXMatrixIdentity(&m_d3dViewMatrix);
m_needBeginScene = true;
m_stickyAlloc = 0;
m_stickyAllocSize = 0;
{
// Check for multitexture.
D3DDEVICEDESC7 deviceCaps;
HRESULT hr = m_pD3DDev->GetCaps(&deviceCaps);
if ( ! FAILED(hr)) {
// Clamp texture blend stages to 2. Some cards can do eight, but that's more
// than we need.
int maxStages = deviceCaps.wMaxTextureBlendStages;
if ( maxStages > 2 ){
maxStages = 2;
}
m_textureState.SetMaxStages(maxStages);
m_hardwareTandL = (deviceCaps.dwDevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0;
for(int i = 0; i < maxStages; i++ ) {
m_pD3DDev->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, i);
}
}
}
// One-time render state initialization
m_pD3DDev->SetRenderState( D3DRENDERSTATE_TEXTUREFACTOR, 0x00000000 );
m_pD3DDev->SetRenderState( D3DRENDERSTATE_DITHERENABLE, TRUE );
m_pD3DDev->SetRenderState( D3DRENDERSTATE_SPECULARENABLE, FALSE );
m_pD3DDev->SetRenderState( D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE );
m_pD3DDev->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
}
~FakeGL(){
delete [] m_stickyAlloc;
ReleaseD3DX();
RELEASENULL(m_modelViewMatrixStack);
RELEASENULL(m_projectionMatrixStack);
RELEASENULL(m_textureMatrixStack);
}
void cglAlphaFunc (GLenum func, GLclampf ref){
if ( m_glAlphaFunc != func || m_glAlphaFuncRef != ref ) {
SetRenderStateDirty();
m_glAlphaFunc = func;
m_glAlphaFuncRef = ref;
m_glAlphaStateDirty = true;
}
}
void cglBegin (GLenum mode){
if ( m_needBeginScene ){
HRESULT hr = m_pD3DDev->BeginScene();
if ( FAILED(hr) ) {
InterpretError(hr);
return;
}
else
m_needBeginScene = false;
}
#if 0
// statistics
static int beginCount;
static int stateChangeCount;
static int primitivesCount;
beginCount++;
if ( m_glRenderStateDirty )
stateChangeCount++;
if ( m_glRenderStateDirty || ! m_OGLPrimitiveVertexBuffer.IsMergableMode(mode) )
primitivesCount++;
#endif
if ( m_glRenderStateDirty || ! m_OGLPrimitiveVertexBuffer.IsMergableMode(mode) ) {
internalEnd();
SetGLRenderState();
DWORD typeDesc;
typeDesc = D3DFVF_XYZ | D3DFVF_DIFFUSE;
typeDesc |= (m_textureState.GetMaxStages() << D3DFVF_TEXCOUNT_SHIFT);
if ( typeDesc != m_OGLPrimitiveVertexBuffer.GetVertexTypeDesc()) {
m_OGLPrimitiveVertexBuffer.Initialize(m_pD3DDev, m_pD3D, m_hardwareTandL, typeDesc);
}
m_OGLPrimitiveVertexBuffer.Begin(mode);
}
else {
m_OGLPrimitiveVertexBuffer.Append(mode);
}
}
void cglBindTexture(GLenum target, GLuint texture){
if ( target != GL_TEXTURE_2D ) {
LocalDebugBreak();
return;
}
if ( m_textureState.GetCurrentTexture() != texture ) {
SetRenderStateDirty();
m_textureState.SetCurrentTexture(texture);
m_textures.BindTexture(texture);
}
}
inline void cglMTexCoord2fSGIS(GLenum target, GLfloat s, GLfloat t){
int textStage = target - TEXTURE0_SGIS;
m_OGLPrimitiveVertexBuffer.SetTextureCoord(textStage, s, t);
}
void cglSelectTextureSGIS(GLenum target){
int textStage = target - TEXTURE0_SGIS;
m_textureState.SetCurrentStage(textStage);
m_textures.BindTexture(m_textureState.GetCurrentTexture());
// Does not, by itself, dirty the render state
}
void cglBlendFunc (GLenum sfactor, GLenum dfactor){
if ( m_glBlendFuncSFactor != sfactor || m_glBlendFuncDFactor != dfactor ) {
SetRenderStateDirty();
m_glBlendFuncSFactor = sfactor;
m_glBlendFuncDFactor = dfactor;
m_glBlendStateDirty = true;
}
}
void cglClear (GLbitfield mask){
HRESULT hr;
internalEnd();
SetGLRenderState();
DWORD clearMask = 0;
if ( mask & GL_COLOR_BUFFER_BIT ) {
clearMask |= D3DCLEAR_TARGET;
}
if ( mask & GL_DEPTH_BUFFER_BIT ) {
clearMask |= D3DCLEAR_ZBUFFER;
}
#ifdef USE_D3DXCONTEXT
hr = m_pD3DX->Clear(clearMask);
#endif
#ifdef USE_D3DFRAME
hr = m_pD3DDev->Clear( 0, 0, clearMask, m_clearColor, 1.0f, 0L );
#endif
if ( FAILED(hr) ){
InterpretError(hr);
}
}
void cglClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha){
D3DCOLOR clearColor = D3DRGBA(Clamp(red), Clamp(green), Clamp(blue), Clamp(alpha));
#ifdef USE_D3DXCONTEXT
HRESULT hr = m_pD3DX->SetClearColor(clearColor);
if( FAILED(hr) ) {
InterpretError(hr);
}
#endif
#ifdef USE_D3DFRAME
m_clearColor = clearColor;
#endif
}
inline void cglColor3f (GLfloat red, GLfloat green, GLfloat blue){
// Note: On x86 architectures this function will chew up a lot of time
// converting floating point to integer by calling _ftol
// unless the /QIfist flag is specified.
m_OGLPrimitiveVertexBuffer.SetColor(D3DRGB(Clamp(red), Clamp(green), Clamp(blue)));
}
inline void cglColor3ubv (const GLubyte *v){
m_OGLPrimitiveVertexBuffer.SetColor(RGBA_MAKE(v[0], v[1], v[2], 0xff));
}
inline void cglColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha){
// Note: On x86 architectures this function will chew up a lot of time
// converting floating point to integer by calling _ftol
// unless the /QIfist flag is specified.
m_OGLPrimitiveVertexBuffer.SetColor(D3DRGBA(Clamp(red), Clamp(green), Clamp(blue), Clamp(alpha)));
}
inline void cglColor4fv (const GLfloat *v){
// Note: On x86 architectures this function will chew up a lot of time
// converting floating point to integer by calling _ftol
// unless the /QIfist flag is specified.
m_OGLPrimitiveVertexBuffer.SetColor(D3DRGBA(Clamp(v[0]), Clamp(v[1]), Clamp(v[2]), Clamp(v[3])));
}
void cglCullFace (GLenum mode){
if ( m_glCullFaceMode != mode ) {
SetRenderStateDirty();
m_glCullFaceMode = mode;
m_glCullStateDirty = true;
}
}
void cglDepthFunc (GLenum func){
if ( m_glDepthFunc != func ) {
SetRenderStateDirty();
m_glDepthFunc = func;
m_glDepthStateDirty = true;
}
}
void cglDepthMask (GLboolean flag){
if ( m_glDepthMask != (flag != 0) ) {
SetRenderStateDirty();
m_glDepthMask = flag != 0 ? true : false;
m_glDepthStateDirty = true;
}
}
void cglDepthRange (GLclampd zNear, GLclampd zFar){
if ( m_glDepthRangeNear != zNear || m_glDepthRangeFar != zFar ) {
SetRenderStateDirty();
m_glDepthRangeNear = zNear;
m_glDepthRangeFar = zFar;
m_bViewPortDirty = true;
}
}
void cglDisable (GLenum cap){
EnableDisableSet(cap, false);
}
void cglDrawBuffer (GLenum /* mode */){
// Do nothing. (Can DirectX render to the front buffer at all?)
}
void cglEnable (GLenum cap){
EnableDisableSet(cap, true);
}
void EnableDisableSet(GLenum cap, bool value){
switch ( cap ) {
case GL_ALPHA_TEST:
if ( m_glAlphaTest != value ) {
SetRenderStateDirty();
m_glAlphaTest = value;
m_glAlphaStateDirty = true;
}
break;
case GL_BLEND:
if ( m_glBlend != value ) {
SetRenderStateDirty();
m_textureState.SetMainBlend(value);
m_glBlend = value;
m_glBlendStateDirty = true;
}
break;
case GL_CULL_FACE:
if ( m_glCullFace != value ) {
SetRenderStateDirty();
m_glCullFace = value;
m_glCullStateDirty = true;
}
break;
case GL_DEPTH_TEST:
if ( m_glDepthTest != value ) {
SetRenderStateDirty();
m_glDepthTest = value;
m_glDepthStateDirty = true;
}
break;
case GL_TEXTURE_2D:
if ( m_textureState.GetTexture2D() != value ) {
SetRenderStateDirty();
m_textureState.SetTexture2D(value);
}
break;
case GL_TEXTURE_GEN_S:
case GL_TEXTURE_GEN_T:
break;
case GL_NORMALIZE:
break;
case GL_AUTO_NORMAL:
break;
case GL_DITHER:
case GL_FOG:
break;
case GL_POLYGON_OFFSET_FILL: // I fear for the shaders.
break;
default:
LocalDebugBreak();
break;
}
}
void cglEnd (void){
// internalEnd();
}
void internalEnd(){
m_OGLPrimitiveVertexBuffer.End();
}
void cglFinish (void){
// To Do: This is supposed to flush all pending commands
internalEnd();
}
void cglFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar){
SetRenderStateDirty();
D3DXMATRIX m;
// Note that D3D takes top, bottom arguments in opposite order
qD3DXMatrixPerspectiveOffCenter(&m, left, right, bottom, top, zNear, zFar);
m_currentMatrixStack->MultMatrixLocal(&m);
*m_currentMatrixStateDirty = true;
}
void cglGetFloatv (GLenum pname, GLfloat *params){
switch(pname){
case GL_MODELVIEW_MATRIX:
memcpy(params,m_modelViewMatrixStack->GetTop(), sizeof(D3DMATRIX));
break;
default:
LocalDebugBreak();
break;
}
}
const GLubyte * cglGetString (GLenum name){
const char* result = "";
EnsureDriverInfo();
switch ( name ) {
case GL_VENDOR:
result = m_vendor;
break;
case GL_RENDERER:
result = m_renderer;
break;
case GL_VERSION:
result = m_version;
break;
case GL_EXTENSIONS:
result = m_extensions;
break;
default:
break;
}
return (const GLubyte *) result;
}
void cglHint (GLenum /* target */, GLenum /* mode */){
LocalDebugBreak();
}
void cglLoadIdentity (void){
SetRenderStateDirty();
m_currentMatrixStack->LoadIdentity();
*m_currentMatrixStateDirty = true;
}
void cglLoadMatrixf (const GLfloat *m){
SetRenderStateDirty();
m_currentMatrixStack->LoadMatrix((D3DXMATRIX*) m);
*m_currentMatrixStateDirty = true;
}
void cglMultMatrixf (const GLfloat *m){
SetRenderStateDirty();
m_currentMatrixStack->MultMatrixLocal((D3DXMATRIX*) m);
*m_currentMatrixStateDirty = true;
}
void cglMatrixMode (GLenum mode){
m_glMatrixMode = mode;
switch ( mode ) {
case GL_MODELVIEW:
m_currentMatrixStack = m_modelViewMatrixStack;
m_currentMatrixStateDirty = &m_modelViewMatrixStateDirty;
break;
case GL_PROJECTION:
m_currentMatrixStack = m_projectionMatrixStack;
m_currentMatrixStateDirty = &m_projectionMatrixStateDirty;
break;
case GL_TEXTURE:
m_currentMatrixStack = m_textureMatrixStack;
m_currentMatrixStateDirty = &m_textureMatrixStateDirty;
break;
default:
LocalDebugBreak();
break;
}
}
void cglOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar){
SetRenderStateDirty();
D3DXMATRIX m;
qD3DXMatrixOrthoOffCenter(&m, left, right, top, bottom, zNear, zFar);
m_currentMatrixStack->MultMatrixLocal(&m);
*m_currentMatrixStateDirty = true;
}
void cglPolygonMode (GLenum face, GLenum mode){
SetRenderStateDirty();
switch ( face ) {
case GL_FRONT:
m_glPolygonModeFront = mode;
break;
case GL_BACK:
m_glPolygonModeBack = mode;
break;
case GL_FRONT_AND_BACK:
m_glPolygonModeFront = mode;
m_glPolygonModeBack = mode;
break;
default:
LocalDebugBreak();
break;
}
}
void cglPopMatrix (void){
SetRenderStateDirty();
m_currentMatrixStack->Pop();
*m_currentMatrixStateDirty = true;
}
void cglPushMatrix (void){
m_currentMatrixStack->Push();
// Doesn't dirty matrix state
}
void cglReadBuffer (GLenum /* mode */){
// Not that we allow reading from various buffers anyway.
}
void cglReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels){
if ( format != GL_RGB || type != GL_UNSIGNED_BYTE) {
LocalDebugBreak();
return;
}
internalEnd();
#ifdef USE_D3DXCONTEXT
LPDIRECTDRAWSURFACE7 back = m_pD3DX->GetBackBuffer(0);
#endif
#ifdef USE_D3DFRAME
LPDIRECTDRAWSURFACE7 back = m_pFramework->GetBackBuffer();
#endif
if(back) {
DDSURFACEDESC2 desc = {sizeof(desc) };
HRESULT hr = back->Lock(NULL, &desc, DDLOCK_READONLY | DDLOCK_WAIT, 0);
if ( FAILED(hr) ) {
InterpretError(hr);
return;
}
CopyBitsToRGB(pixels, x, y, width, height, &desc);
back->Unlock(NULL);
RELEASENULL(back);
}
}
static WORD GetNumberOfBits( DWORD dwMask )
{
WORD wBits = 0;
while( dwMask )
{
dwMask = dwMask & ( dwMask - 1 );
wBits++;
}
return wBits;
}
static WORD GetShift( DWORD dwMask )
{
for(WORD i = 0; i < 32; i++ ) {
if ( (1 << i) & dwMask ) {
return i;
}
}
return 0; // no bits in mask.
}
// Extract the bits and replicate out to an eight bit value
static DWORD ExtractAndNormalize(DWORD rgba, DWORD shift, DWORD bits, DWORD mask){
DWORD v = (rgba & mask) >> shift;
// Assume bits >= 4
v = (v | (v << bits));
v = v >> (bits*2 - 8);
return v;
}
void CopyBitsToRGB(void* pixels, DWORD sx, DWORD sy, DWORD width, DWORD height, LPDDSURFACEDESC2 pDesc){
if ( ! (pDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) ) {
return; // Can't handle non-RGB surfaces
}
// We have to flip the Y axis to convert from D3D to openGL
long destEndOfLineSkip = -2 * (width * 3);
unsigned char* pDest = ((unsigned char*) pixels) + (height - 1) * width * 3 ;
switch ( pDesc->ddpfPixelFormat.dwRGBBitCount ) {
default:
return;
case 16:
{
unsigned short* pSource = (unsigned short*)
(((unsigned char*) pDesc->lpSurface) + sx * sizeof(unsigned short) + sy * pDesc->lPitch);
DWORD endOfLineSkip = pDesc->lPitch / sizeof(unsigned short) - pDesc->dwWidth;
DWORD rMask = pDesc->ddpfPixelFormat.dwRBitMask;
DWORD gMask = pDesc->ddpfPixelFormat.dwGBitMask;
DWORD bMask = pDesc->ddpfPixelFormat.dwBBitMask;
DWORD rShift = GetShift(rMask);
DWORD rBits = GetNumberOfBits(rMask);
DWORD gShift = GetShift(gMask);
DWORD gBits = GetNumberOfBits(gMask);
DWORD bShift = GetShift(bMask);
DWORD bBits = GetNumberOfBits(bMask);
for(DWORD y = 0; y < height; y++ ) {
for (DWORD x = 0; x < width; x++ ) {
unsigned short rgba = *pSource++;
*pDest++ = ExtractAndNormalize(rgba, rShift, rBits, rMask);
*pDest++ = ExtractAndNormalize(rgba, gShift, gBits, gMask);
*pDest++ = ExtractAndNormalize(rgba, bShift, bBits, bMask);
}
pSource += endOfLineSkip;
pDest += destEndOfLineSkip;
}
}
break;
case 32:
{
unsigned long* pSource = (unsigned long*)
(((unsigned char*) pDesc->lpSurface) + sx * sizeof(unsigned long) + sy * pDesc->lPitch);
DWORD endOfLineSkip = pDesc->lPitch / sizeof(unsigned long) - pDesc->dwWidth;
for(DWORD y = 0; y < height; y++ ) {
for (DWORD x = 0; x < width; x++ ) {
unsigned long rgba = *pSource++;
*pDest++ = RGBA_GETRED(rgba);
*pDest++ = RGBA_GETGREEN(rgba);
*pDest++ = RGBA_GETBLUE(rgba);
}
pSource += endOfLineSkip;
pDest += destEndOfLineSkip;
}
}
break;
}
}
void cglRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z){
SetRenderStateDirty();
D3DXMATRIX m;
D3DXVECTOR3 v;
v.x = x;
v.y = y;
v.z = z;
// GL uses counterclockwise degrees, DX uses clockwise radians
float dxAngle = angle * 3.14159 / 180;
m_currentMatrixStack->RotateAxisLocal(&v, dxAngle);
*m_currentMatrixStateDirty = true;
}
void cglScalef (GLfloat x, GLfloat y, GLfloat z){
SetRenderStateDirty();
D3DXMATRIX m;
qD3DXMatrixScaling(&m, x, y, z);
m_currentMatrixStack->MultMatrixLocal(&m);
*m_currentMatrixStateDirty = true;
}
void cglShadeModel (GLenum mode){
if ( m_glShadeModel != mode ) {
SetRenderStateDirty();
m_glShadeModel = mode;
m_glShadeModelStateDirty = true;
}
}
inline void cglTexCoord2f (GLfloat s, GLfloat t){
m_OGLPrimitiveVertexBuffer.SetTextureCoord0(s, t);
}
void cglTexEnvf (GLenum /* target */, GLenum /* pname */, GLfloat param){
// ignore target, which must be GL_TEXTURE_ENV
// ignore pname, which must be GL_TEXTURE_ENV_MODE
if ( m_textureState.GetTextEnvMode() != param ) {
SetRenderStateDirty();
m_textureState.SetTextEnvMode(param);
}
}
static int MipMapSize(DWORD width, DWORD height){
DWORD n = width < height? width : height;
DWORD result = 1;
while (n > (DWORD) (1 << result) ) {
result++;
}
return result;
}
#define LOAD_OURSELVES
void cglTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width,
GLsizei height, GLint /* border */, GLenum format, GLenum type, const GLvoid *pixels){
HRESULT hr;
if ( target != GL_TEXTURE_2D || type != GL_UNSIGNED_BYTE) {
InterpretError(E_FAIL);
return;
}
bool isDynamic = format == GL_LUMINANCE; // Lightmaps use this format.
DWORD dxWidth = width;
DWORD dxHeight = height;
D3DX_SURFACEFORMAT srcPixelFormat = GLToDXPixelFormat(internalformat, format);
D3DX_SURFACEFORMAT destPixelFormat = srcPixelFormat;
// Can the surface handle that format?
hr = qD3DXCheckTextureRequirements(m_pD3DDev, NULL, &dxWidth, &dxHeight, &destPixelFormat);
if ( FAILED(hr) ) {
if ( g_force16bitTextures ) {
destPixelFormat = D3DX_SF_A4R4G4B4;
hr = qD3DXCheckTextureRequirements(m_pD3DDev, NULL, NULL, NULL, &destPixelFormat);
if ( FAILED(hr) ) {
// Don't know what to do.
InterpretError(E_FAIL);
return;
}
}
else {
destPixelFormat = D3DX_SF_A8R8G8B8;
hr = qD3DXCheckTextureRequirements(m_pD3DDev, NULL, NULL, NULL, &destPixelFormat);
if ( FAILED(hr) ) {
// The card can't handle this pixel format. Switch to D3DX_SF_A4R4G4B4
destPixelFormat = D3DX_SF_A4R4G4B4;
hr = qD3DXCheckTextureRequirements(m_pD3DDev, NULL, NULL, NULL, &destPixelFormat);
if ( FAILED(hr) ) {
// Don't know what to do.
InterpretError(E_FAIL);
return;
}
}
}
}
#ifdef LOAD_OURSELVES
char* goodSizeBits = (char*) pixels;
if ( dxWidth != (DWORD) width || dxHeight != (DWORD) height ) {
// Most likely this is because there is a 256 x 256 limit on the texture size.
goodSizeBits = new char[sizeof(DWORD) * dxWidth * dxHeight];
DWORD* dest = ((DWORD*) goodSizeBits);
for ( DWORD y = 0; y < dxHeight; y++) {
DWORD sy = y * height / dxHeight;
for(DWORD x = 0; x < dxWidth; x++) {
DWORD sx = x * width / dxWidth;
DWORD* source = ((DWORD*) pixels) + sy * dxWidth + sx;
*dest++ = *source;
}
}
width = dxWidth;
height = dxHeight;
}
// To do: Convert the pixels on the fly while copying into the DX texture.
char* compatablePixels;
DWORD compatablePixelsPitch;
hr = ConvertToCompatablePixels(internalformat, width, height, format,
type, destPixelFormat, goodSizeBits, &compatablePixels, &compatablePixelsPitch);
if ( goodSizeBits != pixels ) {
delete [] goodSizeBits;
}
if ( FAILED(hr)) {
InterpretError(hr);
return;
}
#endif
// It the current texture of the right size?
LPDIRECTDRAWSURFACE7 pTexture = m_textures.GetTexture();
if ( pTexture ) {
DDSURFACEDESC2 surface;
memset(&surface, 0, sizeof(surface));
surface.dwSize = sizeof(surface);
hr = pTexture->GetSurfaceDesc(&surface);
if ( FAILED(hr) ) {
InterpretError(hr);
return;
}
// Is this texture being resized or re-color-formatted?
if ( level == 0 &&
( surface.dwWidth != (DWORD) width || surface.dwHeight != (DWORD) height
|| destPixelFormat != m_textures.GetCurrentEntry()->m_format)) {
m_textures.SetTexture(NULL, D3DX_SF_UNKNOWN, 0);
pTexture = 0;
}
// For non-square textures, OpenGL uses more MIPMAP levels than DirectX does.
else if ( (surface.dwWidth >> level) <= 0 || (surface.dwHeight >> level) <= 0 ) {
return;
}
}
if( ! pTexture) {
#ifdef USE_D3DXCREATETEXTURE
DWORD dxwidth = width;
DWORD dxheight = height;
D3DX_SURFACEFORMAT pixelFormat = destPixelFormat;
DWORD numMapsGenerated = 0;
hr = D3DXCreateTexture(m_pD3DDev, NULL, &dxwidth, &dxheight, &pixelFormat,
NULL, &pTexture, &numMapsGenerated);
if ( FAILED(hr) ) {
InterpretError(hr);
return;
}
#else
DDSURFACEDESC2 sd = {sizeof(sd)};
D3DX_SURFACEFORMAT pixelFormat = destPixelFormat;
sd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|
DDSD_PIXELFORMAT;
sd.dwHeight = dxHeight;
sd.dwWidth = dxWidth;
qD3DXMakeDDPixelFormat(pixelFormat, &sd.ddpfPixelFormat);
sd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
if ( m_hintGenerateMipMaps ) {
sd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP|DDSCAPS_COMPLEX;
}
sd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
if ( isDynamic ) {
sd.ddsCaps.dwCaps2 |= DDSCAPS2_HINTDYNAMIC;
}
else {
sd.ddsCaps.dwCaps2 |= DDSCAPS2_OPAQUE; // DDSCAPS2_HINTSTATIC;
}
hr = m_pDD->CreateSurface(&sd, &pTexture, NULL);
if ( FAILED(hr) ) {
InterpretError(hr);
return;
}
int bytesThisTexture = height * compatablePixelsPitch;
if ( m_hintGenerateMipMaps ) {
bytesThisTexture = bytesThisTexture * 4 / 3;
}
static int gNumBytesOfTextures = 0; // For debugging
gNumBytesOfTextures += bytesThisTexture;
#endif
m_textures.SetTexture(pTexture, pixelFormat, internalformat);
}
#ifdef LOAD_OURSELVES
glTexSubImage2D_Imp(pTexture, level, 0, 0, width, height, format, type, compatablePixels,
compatablePixelsPitch);
#else
// This function is useful because it can scale large textures to fit into smaller textures.
hr = D3DXLoadTextureFromMemory(m_pD3DDev, pTexture, level, (void*) pixels, NULL, srcPixelFormat, D3DX_DEFAULT,
NULL, D3DX_FT_DEFAULT);
#endif
if ( FAILED(hr) ) {
InterpretError(hr);
return;
}
}
void cglTexParameterf (GLenum target, GLenum pname, GLfloat param){
switch(target){
case GL_TEXTURE_2D:
{
SetRenderStateDirty();
TextureEntry* current = m_textures.GetCurrentEntry();
m_textureState.DirtyTexture(m_textures.GetCurrentID());
switch(pname) {
case GL_TEXTURE_MIN_FILTER:
current->m_glTexParameter2DMinFilter = param;
break;
case GL_TEXTURE_MAG_FILTER:
current->m_glTexParameter2DMagFilter = param;
break;
case GL_TEXTURE_WRAP_S:
current->m_glTexParameter2DWrapS = param;
break;
case GL_TEXTURE_WRAP_T:
current->m_glTexParameter2DWrapT = param;
break;
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
current->m_maxAnisotropy = param;
break;
default:
LocalDebugBreak();
}
}
break;
default:
LocalDebugBreak();
break;
}
}
void cglTexSubImage2D (GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLenum format, GLenum type, const GLvoid *pixels){
if ( target != GL_TEXTURE_2D ) {
LocalDebugBreak();
return;
}
if ( width <= 0 || height <= 0 ) {
return;
}
LPDIRECTDRAWSURFACE7 pTexture = m_textures.GetTexture();
if ( ! pTexture ) {
return;
}
internalEnd(); // We may have a pending drawing using the old texture state.
// To do: Convert the pixels on the fly while copying into the DX texture.
char* compatablePixels = 0;
DWORD compatablePixelsPitch;
if ( FAILED(ConvertToCompatablePixels(m_textures.GetInternalFormat(),
width, height,
format, type, m_textures.GetSurfaceFormat(),
pixels, &compatablePixels, &compatablePixelsPitch))) {
LocalDebugBreak();
return;
}
glTexSubImage2D_Imp(pTexture, level, xoffset, yoffset, width, height, format, type,
compatablePixels, compatablePixelsPitch);
}
char* StickyAlloc(DWORD size){
if ( m_stickyAllocSize < size ) {
delete [] m_stickyAlloc;
m_stickyAlloc = new char[size];
m_stickyAllocSize = size;
}
return m_stickyAlloc;
}
void glTexSubImage2D_Imp (LPDIRECTDRAWSURFACE7 pTexture, GLint level,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLenum /* format */, GLenum /* type */, const char* compatablePixels, int compatablePixelsPitch){
HRESULT hr = S_OK;
// Walk MIPMAP chain
LPDIRECTDRAWSURFACE7 lpDDLevel;
{
LPDIRECTDRAWSURFACE7 lpDDNextLevel;
DDSCAPS2 ddsCaps;
lpDDLevel = pTexture;
lpDDLevel->AddRef();
memset(&ddsCaps, 0, sizeof(ddsCaps));
ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
hr = DD_OK;
while (hr == DD_OK && level > 0)
{
hr = lpDDLevel->GetAttachedSurface(&ddsCaps, &lpDDNextLevel);
lpDDLevel->Release();
lpDDLevel = lpDDNextLevel;
level--;
}
}
if ( FAILED(hr) ) {
InterpretError(hr);
RELEASENULL(lpDDLevel);
return;
}
DDSURFACEDESC2 surfaceDesc;
memset(&surfaceDesc, 0, sizeof(DDSURFACEDESC2));
surfaceDesc.dwSize = sizeof(DDSURFACEDESC2);
RECT lockRect;
lockRect.top = yoffset;
lockRect.left = xoffset;
lockRect.bottom = yoffset + height;
lockRect.right = xoffset + width;
hr = lpDDLevel->Lock(&lockRect, &surfaceDesc,
DDLOCK_NOSYSLOCK|DDLOCK_WAIT|DDLOCK_WRITEONLY, NULL);
if ( FAILED(hr) ) {
InterpretError(hr);
}
else {
const char* sp = compatablePixels;
char* dp = (char*) surfaceDesc.lpSurface;
if ( compatablePixelsPitch != surfaceDesc.lPitch ) {
for(int i = 0; i < height; i++ ) {
memcpy(dp, sp, compatablePixelsPitch);
sp += compatablePixelsPitch;
dp += surfaceDesc.lPitch;
}
}
else {
memcpy(dp, sp, compatablePixelsPitch * height);
}
lpDDLevel->Unlock(&lockRect);
}
RELEASENULL(lpDDLevel);
if ( FAILED(hr) ) {
InterpretError(hr);
}
}
void cglTranslatef (GLfloat x, GLfloat y, GLfloat z){
SetRenderStateDirty();
D3DXMATRIX m;
qD3DXMatrixTranslation(&m, x, y, z);
m_currentMatrixStack->MultMatrixLocal(&m);
*m_currentMatrixStateDirty = true;
}
inline void cglVertex2f (GLfloat x, GLfloat y){
m_OGLPrimitiveVertexBuffer.SetVertex(x, y, 0);
}
inline void cglVertex3f (GLfloat x, GLfloat y, GLfloat z){
m_OGLPrimitiveVertexBuffer.SetVertex(x, y, z);
}
inline void cglVertex3fv (const GLfloat *v){
m_OGLPrimitiveVertexBuffer.SetVertex(v[0], v[1], v[2]);
}
void cglViewport (GLint x, GLint y, GLsizei width, GLsizei height){
if ( m_glViewPortX != x || m_glViewPortY != y ||
m_glViewPortWidth != width || m_glViewPortHeight != height ) {
SetRenderStateDirty();
m_glViewPortX = x;
m_glViewPortY = y;
m_glViewPortWidth = width;
m_glViewPortHeight = height;
m_bViewPortDirty = true;
}
}
void SwapBuffers(){
HRESULT hr = S_OK;
internalEnd();
m_pD3DDev->EndScene();
m_needBeginScene = true;
#ifdef USE_D3DXCONTEXT
hr = m_pD3DX->UpdateFrame( D3DX_UPDATE_NOVSYNC );
if ( hr == DDERR_SURFACELOST || hr == DDERR_SURFACEBUSY )
hr = HandleWindowedModeChanges();
#endif
#ifdef USE_D3DFRAME
if( FAILED( hr = m_pFramework->ShowFrame() ) )
{
if( DDERR_SURFACELOST != hr )
return;
m_pFramework->RestoreSurfaces();
RestoreSurfaces();
}
#endif
}
void SetGammaRamp(const unsigned char* gammaTable){
DDCAPS caps = {sizeof(DDCAPS)};
HRESULT hr;
hr = m_pDD->GetCaps(&caps, NULL);
if ( caps.dwCaps2 & DDCAPS2_PRIMARYGAMMA ) {
DDGAMMARAMP gammaRamp;
for(int i = 0; i < 256; i++ ) {
WORD value = gammaTable[i];
value = value + (value << 8); // * 257
gammaRamp.red[i] = value;
gammaRamp.green[i] = value;
gammaRamp.blue[i] = value;
}
/*
if(m_pPrimary) {
IDirectDrawGammaControl* lpDDGammaControl = 0;
hr = m_pPrimary->QueryInterface(IID_IDirectDrawGammaControl,(void**)&lpDDGammaControl);
if ( ! FAILED(hr) && lpDDGammaControl ) {
DWORD dwFlags = 0;
if ( caps.dwCaps2 & DDCAPS2_CANCALIBRATEGAMMA ) {
dwFlags = DDSGR_CALIBRATE;
}
hr = lpDDGammaControl->SetGammaRamp(dwFlags, &gammaRamp);
RELEASENULL(lpDDGammaControl);
}
}
*/
}
}
void Hint_GenerateMipMaps(int value){
m_hintGenerateMipMaps = value != 0;
}
void EvictTextures(){
m_pD3D->EvictManagedTextures();
}
private:
void SetRenderStateDirty(){
if ( ! m_glRenderStateDirty ) {
internalEnd();
m_glRenderStateDirty = true;
}
}
HRESULT HandleWindowedModeChanges()
{
#ifdef USE_D3DFRAME
return Change3DEnvironment();
#endif
HRESULT hr;
hr = m_pDD->TestCooperativeLevel();
if( SUCCEEDED( hr ) )
{
// This means that mode changes had taken place, surfaces
// were lost but still we are in the original mode, so we
// simply restore all surfaces and keep going.
if( FAILED( m_pDD->RestoreAllSurfaces() ) )
return hr;
}
else if( hr == DDERR_WRONGMODE )
{
// This means that the desktop mode has changed
// we can destroy and recreate everything back again.
if(FAILED(hr = ReleaseD3DX()))
return hr;
if(FAILED(hr = InitD3DX()))
return hr;
}
else if( hr == DDERR_EXCLUSIVEMODEALREADYSET )
{
// This means that some app took exclusive mode access
// we need to sit in a loop till we get back to the right mode.
do
{
Sleep( 500 );
} while( DDERR_EXCLUSIVEMODEALREADYSET ==
(hr = m_pDD->TestCooperativeLevel()) );
if( SUCCEEDED( hr ) )
{
// This means that the exclusive mode app relinquished its
// control and we are back to the safe mode, so simply restore
if( FAILED( m_pDD->RestoreAllSurfaces() ) )
return hr;
}
else if( DDERR_WRONGMODE == hr )
{
// This means that the exclusive mode app relinquished its
// control BUT we are back to some strange mode, so destroy
// and recreate.
if(FAILED(hr = ReleaseD3DX()))
return hr;
if(FAILED(hr = InitD3DX()))
return hr;
}
else
{
// Busted!!
return hr;
}
}
else
{
// Busted!!
return hr;
}
return S_OK;
}
void SetGLRenderState(){
if ( ! m_glRenderStateDirty ) {
return;
}
m_glRenderStateDirty = false;
HRESULT hr;
if ( m_glAlphaStateDirty ){
m_glAlphaStateDirty = false;
// Alpha test
m_pD3DDev->SetRenderState( D3DRENDERSTATE_ALPHATESTENABLE,
m_glAlphaTest ? TRUE : FALSE );
m_pD3DDev->SetRenderState(D3DRENDERSTATE_ALPHAFUNC,
m_glAlphaTest ? GLToDXCompare(m_glAlphaFunc) : D3DCMP_ALWAYS);
m_pD3DDev->SetRenderState(D3DRENDERSTATE_ALPHAREF, 255 * m_glAlphaFuncRef);
}
if ( m_glBlendStateDirty ){
m_glBlendStateDirty = false;
// Alpha blending
DWORD srcBlend = m_glBlend ? GLToDXSBlend(m_glBlendFuncSFactor) : D3DBLEND_ONE;
DWORD destBlend = m_glBlend ? GLToDXDBlend(m_glBlendFuncDFactor) : D3DBLEND_ZERO;
m_pD3DDev->SetRenderState( D3DRENDERSTATE_SRCBLEND, srcBlend );
m_pD3DDev->SetRenderState( D3DRENDERSTATE_DESTBLEND, destBlend );
m_pD3DDev->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, m_glBlend ? TRUE : FALSE );
}
if ( m_glCullStateDirty ) {
m_glCullStateDirty = false;
D3DCULL cull = D3DCULL_NONE;
if ( m_glCullFace ) {
switch(m_glCullFaceMode){
default:
case GL_BACK:
// Should deal with frontface function
cull = D3DCULL_CCW;
break;
}
}
hr = m_pD3DDev->SetRenderState(D3DRENDERSTATE_CULLMODE, cull);
if ( FAILED(hr) ){
InterpretError(hr);
}
}
if ( m_glShadeModelStateDirty ){
m_glShadeModelStateDirty = false;
// Shade model
m_pD3DDev->SetRenderState( D3DRENDERSTATE_SHADEMODE,
m_glShadeModel == GL_SMOOTH ? D3DSHADE_GOURAUD : D3DSHADE_FLAT );
}
{
m_textureState.SetTextureStageState(m_pD3DDev, &m_textures);
}
if ( m_glDepthStateDirty ) {
m_glDepthStateDirty = false;
m_pD3DDev->SetRenderState( D3DRENDERSTATE_ZENABLE, m_glDepthTest ? D3DZB_TRUE : D3DZB_FALSE);
m_pD3DDev->SetRenderState( D3DRENDERSTATE_ZWRITEENABLE, m_glDepthMask ? TRUE : FALSE);
DWORD zfunc = GLToDXCompare(m_glDepthFunc);
m_pD3DDev->SetRenderState( D3DRENDERSTATE_ZFUNC, zfunc );
}
if ( m_modelViewMatrixStateDirty ) {
m_modelViewMatrixStateDirty = false;
m_pD3DDev->SetTransform( D3DTRANSFORMSTATE_WORLD, (LPD3DMATRIX) m_modelViewMatrixStack->GetTop() );
}
if ( m_viewMatrixStateDirty ) {
m_viewMatrixStateDirty = false;
m_pD3DDev->SetTransform( D3DTRANSFORMSTATE_VIEW, (LPD3DMATRIX) & m_d3dViewMatrix );
}
if ( m_projectionMatrixStateDirty ) {
m_projectionMatrixStateDirty = false;
m_pD3DDev->SetTransform( D3DTRANSFORMSTATE_PROJECTION, (LPD3DMATRIX) m_projectionMatrixStack->GetTop() );
}
if ( m_textureMatrixStateDirty ) {
m_textureMatrixStateDirty = false;
m_pD3DDev->SetTransform( D3DTRANSFORMSTATE_TEXTURE0, (LPD3DMATRIX) m_textureMatrixStack->GetTop() );
}
if ( m_bViewPortDirty ) {
m_bViewPortDirty = false;
D3DVIEWPORT7 viewData;
viewData.dwX = m_glViewPortX;
viewData.dwY = m_windowHeight - (m_glViewPortY + m_glViewPortHeight);
viewData.dwWidth = m_glViewPortWidth;
viewData.dwHeight = m_glViewPortHeight;
viewData.dvMinZ = m_glDepthRangeNear;
viewData.dvMaxZ = m_glDepthRangeFar;
if (r_secondaryview)
{
m_pD3DDev->EndScene();
m_needBeginScene = true;
}
m_pD3DDev->SetViewport(&viewData);
}
}
void EnsureDriverInfo() {
if ( ! m_vendor ) {
memset(&m_dddi, 0, sizeof(m_dddi));
m_pDD->GetDeviceIdentifier(&m_dddi, 0);
m_vendor = m_dddi.szDriver;
m_renderer = m_dddi.szDescription;
wsprintf(m_version, "%u.%u.%u.%u %u.%u.%u.%u %u",
HIWORD(m_dddi.liDriverVersion.HighPart),
LOWORD(m_dddi.liDriverVersion.HighPart),
HIWORD(m_dddi.liDriverVersion.LowPart),
LOWORD(m_dddi.liDriverVersion.LowPart),
m_dddi.dwVendorId,
m_dddi.dwDeviceId,
m_dddi.dwSubSysId,
m_dddi.dwRevision,
m_dddi.dwWHQLLevel
);
if ( m_textureState.GetMaxStages() > 1 ) {
m_extensions = " GL_SGIS_multitexture GL_EXT_texture_object ";
}
else {
m_extensions = " GL_EXT_texture_object ";
}
}
}
D3DX_SURFACEFORMAT GLToDXPixelFormat(GLint internalformat, GLenum format){
D3DX_SURFACEFORMAT d3dFormat = D3DX_SF_UNKNOWN;
if ( g_force16bitTextures ) {
switch ( format ) {
case GL_RGBA:
switch ( internalformat ) {
default:
case 4:
// d3dFormat = D3DX_SF_A1R5G5B5; break;
d3dFormat = D3DX_SF_A4R4G4B4; break;
case 3:
d3dFormat = D3DX_SF_R5G6B5; break;
}
break;
case GL_RGB: d3dFormat = D3DX_SF_R5G5B5; break;
case GL_COLOR_INDEX: d3dFormat = D3DX_SF_PALETTE8; break;
case GL_LUMINANCE: d3dFormat = D3DX_SF_L8; break;
case GL_ALPHA: d3dFormat = D3DX_SF_A8; break;
case GL_INTENSITY: d3dFormat = D3DX_SF_L8; break;
case GL_RGBA4: d3dFormat = D3DX_SF_A4R4G4B4; break;
default:
InterpretError(E_FAIL);
}
}
else {
// for
switch ( format ) {
case GL_RGBA:
switch ( internalformat ) {
default:
case 4:
d3dFormat = D3DX_SF_A8R8G8B8; break;
case 3:
d3dFormat = D3DX_SF_X8R8G8B8; break;
}
break;
case GL_RGB:
d3dFormat = D3DX_SF_R8G8B8;
break;
case GL_COLOR_INDEX: d3dFormat = D3DX_SF_PALETTE8; break;
case GL_LUMINANCE: d3dFormat = D3DX_SF_L8; break;
case GL_ALPHA: d3dFormat = D3DX_SF_A8; break;
case GL_INTENSITY: d3dFormat = D3DX_SF_L8; break;
case GL_RGBA4: d3dFormat = D3DX_SF_A4R4G4B4; break;
default:
InterpretError(E_FAIL);
}
}
return d3dFormat;
}
// Avoid warning 4061, enumerant 'foo' in switch of enum 'bar' is not explicitly handled by a case label.
#pragma warning( push )
#pragma warning( disable : 4061)
HRESULT ConvertToCompatablePixels(GLint internalformat,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
D3DX_SURFACEFORMAT dxPixelFormat,
const GLvoid *pixels, char** compatablePixels,
DWORD* newPitch){
HRESULT hr = S_OK;
if ( type != GL_UNSIGNED_BYTE ) {
return E_FAIL;
}
switch ( dxPixelFormat ) {
default:
LocalDebugBreak();
break;
case D3DX_SF_PALETTE8:
case D3DX_SF_L8:
case D3DX_SF_A8:
{
char* copy = StickyAlloc(width*height);
memcpy(copy,pixels,width * height);
*compatablePixels = copy;
if ( newPitch ) {
*newPitch = width;
}
}
break;
case D3DX_SF_A4R4G4B4:
{
int textureElementSize = 2;
const unsigned char* glpixels = (const unsigned char*) pixels;
char* dxpixels = StickyAlloc(textureElementSize * width * height);
switch ( internalformat ) {
default:
LocalDebugBreak();
break;
case 1:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const unsigned char* sp = glpixels + (y*width+x);
unsigned short v;
unsigned short s = 0xf & (sp[0] >> 4);
v = s; // blue
v |= s << 4; // green
v |= s << 8; // red
v |= s << 12; // alpha
*dp = v;
}
}
}
break;
case 3:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const unsigned char* sp = glpixels + (y*width+x)*4;
unsigned short v;
v = (0xf & (sp[2] >> 4)); // blue
v |= (0xf & (sp[1] >> 4)) << 4; // green
v |= (0xf & (sp[0] >> 4)) << 8; // red
v |= 0xf000; // alpha
*dp = v;
}
}
}
break;
case 4:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*)(dxpixels + (y*width+x)*textureElementSize);
const unsigned char* sp = glpixels + (y*width+x)*4;
unsigned short v;
v = (0xf & (sp[2] >> 4)); // blue
v |= (0xf & (sp[1] >> 4)) << 4; // green
v |= (0xf & (sp[0] >> 4)) << 8; // red
v |= (0xf & (sp[3] >> 4)) << 12; // alpha
*dp = v;
}
}
}
break;
}
*compatablePixels = dxpixels;
if ( newPitch ) {
*newPitch = 2 * width;
}
}
break;
case D3DX_SF_R5G6B5:
{
int textureElementSize = 2;
const char* glpixels = (const char*) pixels;
char* dxpixels = StickyAlloc(textureElementSize * width * height);
switch ( internalformat ) {
default:
LocalDebugBreak();
break;
case 1:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const char* sp = glpixels + (y*width+x);
unsigned short v;
v = (0x1f & (sp[0] >> 3)); // blue
v |= (0x3f & (sp[0] >> 2)) << 5; // green
v |= (0x1f & (sp[0] >> 3)) << 11; // red
*dp = v;
}
}
}
break;
case 3:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const char* sp = glpixels + (y*width+x)*4;
unsigned short v;
v = (0x1f & (sp[2] >> 3)); // blue
v |= (0x3f & (sp[1] >> 2)) << 5; // green
v |= (0x1f & (sp[0] >> 3)) << 11; // red
*dp = v;
}
}
}
break;
case 4:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const char* sp = glpixels + (y*width+x)*4;
unsigned short v;
v = (0x1f & (sp[2] >> 3)); // blue
v |= (0x3f & (sp[1] >> 2)) << 5; // green
v |= (0x1f & (sp[0] >> 3)) << 11; // red
*dp = v;
}
}
}
break;
}
*compatablePixels = dxpixels;
if ( newPitch ) {
*newPitch = 2 * width;
}
}
break;
case D3DX_SF_R5G5B5:
{
int textureElementSize = 2;
const char* glpixels = (const char*) pixels;
char* dxpixels = StickyAlloc(textureElementSize * width * height);
switch ( internalformat ) {
default:
LocalDebugBreak();
break;
case 1:
{
#define RGBTOR5G5B5(R, G, B) (0x8000 | (0x1f & ((B) >> 3)) | ((0x1f & ((G) >> 3)) << 5) | ((0x1f & ((R) >> 3)) << 10))
#define Y5TOR5G5B5(Y) (0x8000 | ((Y) << 10) | ((Y) << 5) | (Y))
static const unsigned short table[32] = {
Y5TOR5G5B5(0), Y5TOR5G5B5(1), Y5TOR5G5B5(2), Y5TOR5G5B5(3),
Y5TOR5G5B5(4), Y5TOR5G5B5(5), Y5TOR5G5B5(6), Y5TOR5G5B5(7),
Y5TOR5G5B5(8), Y5TOR5G5B5(9), Y5TOR5G5B5(10), Y5TOR5G5B5(11),
Y5TOR5G5B5(12), Y5TOR5G5B5(13), Y5TOR5G5B5(14), Y5TOR5G5B5(15),
Y5TOR5G5B5(16), Y5TOR5G5B5(17), Y5TOR5G5B5(18), Y5TOR5G5B5(19),
Y5TOR5G5B5(20), Y5TOR5G5B5(21), Y5TOR5G5B5(22), Y5TOR5G5B5(23),
Y5TOR5G5B5(24), Y5TOR5G5B5(25), Y5TOR5G5B5(26), Y5TOR5G5B5(27),
Y5TOR5G5B5(28), Y5TOR5G5B5(29), Y5TOR5G5B5(30), Y5TOR5G5B5(31)
};
unsigned short* dp = (unsigned short*) dxpixels;
const unsigned char* sp = (const unsigned char*) glpixels;
int numPixels = height * width;
int i = numPixels >> 2;
while(i > 0) {
*dp++ = table[(*sp++) >> 3];
*dp++ = table[(*sp++) >> 3];
*dp++ = table[(*sp++) >> 3];
*dp++ = table[(*sp++) >> 3];
--i;
}
i = numPixels & 3;
while(i > 0) {
*dp++ = table[(*sp++) >> 3];
--i;
}
}
break;
case 3:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const unsigned char* sp = (const unsigned char*) glpixels + (y*width+x)*4;
unsigned short v;
v = (sp[2] >> 3); // blue
v |= (sp[1] >> 3) << 5; // green
v |= (sp[0] >> 3) << 10; // red
v |= 0x8000; // alpha
*dp = v;
}
}
}
break;
case 4:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const unsigned char* sp = (const unsigned char*) glpixels + (y*width+x)*4;
unsigned short v;
v = (sp[2] >> 3); // blue
v |= (sp[1] >> 3) << 5; // green
v |= (sp[0] >> 3) << 10; // red
v |= 0x8000; // alpha
*dp = v;
}
}
}
break;
}
*compatablePixels = dxpixels;
if ( newPitch ) {
*newPitch = 2 * width;
}
}
break;
case D3DX_SF_A1R5G5B5:
{
int textureElementSize = 2;
const char* glpixels = (const char*) pixels;
char* dxpixels = StickyAlloc(textureElementSize * width * height);
switch ( internalformat ) {
default:
LocalDebugBreak();
break;
case 1:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const char* sp = glpixels + (y*width+x);
unsigned short v;
v = (0x1f & (sp[0] >> 3)); // blue
v |= (0x1f & (sp[0] >> 3)) << 5; // green
v |= (0x1f & (sp[0] >> 3)) << 10; // red
v |= (0x01 & (sp[0] >> 7)) << 15; // alpha
*dp = v;
}
}
}
break;
case 3:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const char* sp = glpixels + (y*width+x)*4;
unsigned short v;
v = (0x1f & (sp[2] >> 3)); // blue
v |= (0x1f & (sp[1] >> 3)) << 5; // green
v |= (0x1f & (sp[0] >> 3)) << 10; // red
v |= 0x8000; // alpha
*dp = v;
}
}
}
break;
case 4:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned short* dp = (unsigned short*) (dxpixels + (y*width+x)*textureElementSize);
const char* sp = glpixels + (y*width+x)*4;
unsigned short v;
v = (0x1f & (sp[2] >> 3)); // blue
v |= (0x1f & (sp[1] >> 3)) << 5; // green
v |= (0x1f & (sp[0] >> 3)) << 10; // red
v |= (0x01 & (sp[3] >> 7)) << 15; // alpha
*dp = v;
}
}
}
break;
}
*compatablePixels = dxpixels;
if ( newPitch ) {
*newPitch = 2 * width;
}
}
break;
case D3DX_SF_X8R8G8B8:
case D3DX_SF_A8R8G8B8:
{
int textureElementSize = 4;
const char* glpixels = (const char*) pixels;
char* dxpixels = StickyAlloc(textureElementSize * width * height);
switch ( internalformat ) {
default:
LocalDebugBreak();
break;
case 1:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
char* dp = dxpixels + (y*width+x)*textureElementSize;
const char* sp = glpixels + (y*width+x);
dp[0] = sp[0]; // blue
dp[1] = sp[0]; // green
dp[2] = sp[0]; // red
dp[3] = sp[0];
}
}
}
break;
case 3:
if (format == GL_RGB)
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned char* dp = (unsigned char*) dxpixels + (y*width+x)*textureElementSize;
const unsigned char* sp = (unsigned char*) glpixels + (y*width+x)*3;
dp[0] = sp[2]; // blue
dp[1] = sp[1]; // green
dp[2] = sp[0]; // red
dp[3] = 0xff;
}
}
}
else
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
unsigned char* dp = (unsigned char*) dxpixels + (y*width+x)*textureElementSize;
const unsigned char* sp = (unsigned char*) glpixels + (y*width+x)*4;
dp[0] = sp[2]; // blue
dp[1] = sp[1]; // green
dp[2] = sp[0]; // red
dp[3] = 0xff;
}
}
}
break;
case 4:
{
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
char* dp = dxpixels + (y*width+x)*textureElementSize;
const char* sp = glpixels + (y*width+x)*4;
dp[0] = sp[2]; // blue
dp[1] = sp[1]; // green
dp[2] = sp[0]; // red
dp[3] = sp[3]; // alpha
}
}
}
break;
}
*compatablePixels = dxpixels;
if ( newPitch ) {
*newPitch = 4 * width;
}
}
}
return hr;
}
};
#pragma warning( pop )
// TODO Fix this warning instead of disableing it
#pragma warning(disable:4273)
void APIENTRY D3DAlphaFunc (GLenum func, GLclampf ref){
gFakeGL->cglAlphaFunc(func, ref);
}
void APIENTRY D3DBegin (GLenum mode){
gFakeGL->cglBegin(mode);
}
void APIENTRY D3DBlendFunc (GLenum sfactor, GLenum dfactor){
gFakeGL->cglBlendFunc(sfactor, dfactor);
}
void APIENTRY D3DClear (GLbitfield mask){
gFakeGL->cglClear(mask);
}
void APIENTRY D3DClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha){
gFakeGL->cglClearColor(red, green, blue, alpha);
}
void APIENTRY D3DColor3f (GLfloat red, GLfloat green, GLfloat blue){
if (red > 1) red = 1;
if (green > 1) green = 1;
if (blue > 1) blue = 1;
if (red < 0) red = 0;
if (green < 0) green = 0;
if (blue < 0) blue = 0;
gFakeGL->cglColor3f(red, green, blue);
}
void APIENTRY D3DColor3ubv (const GLubyte *v){
gFakeGL->cglColor3ubv(v);
}
void APIENTRY D3DColor3ub (GLubyte v1, GLubyte v2, GLubyte v3)
{
gFakeGL->cglColor3f(v1/255.0, v2/255.0, v3/255.0);
}
void APIENTRY D3DColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha){
if (red>1) red = 1;
if (green>1) green = 1;
if (blue>1) blue = 1;
if (alpha>1) alpha = 1;
if (red < 0) red = 0;
if (green < 0) green = 0;
if (blue < 0) blue = 0;
if (alpha < 0) alpha = 0;
gFakeGL->cglColor4f(red, green, blue, alpha);
}
void APIENTRY D3DColor4fv (const GLfloat *v){
gFakeGL->cglColor4fv(v);
}
void APIENTRY D3DColor4ubv (const GLubyte *v) //no bounds checking needed
{
gFakeGL->cglColor4f(v[0]/255.0, v[1]/255.0, v[2]/255.0, v[3]/255.0);
}
void APIENTRY D3DColor4ub (GLubyte v1, GLubyte v2, GLubyte v3, GLubyte v4)
{
gFakeGL->cglColor4f(v1/255.0, v2/255.0, v3/255.0, v4/255.0);
}
void APIENTRY D3DCullFace (GLenum mode){
gFakeGL->cglCullFace(mode);
}
void APIENTRY D3DDepthFunc (GLenum func){
gFakeGL->cglDepthFunc(func);
}
void APIENTRY D3DDepthMask (GLboolean flag){
gFakeGL->cglDepthMask(flag);
}
void APIENTRY D3DDepthRange (GLclampd zNear, GLclampd zFar){
gFakeGL->cglDepthRange(zNear, zFar);
}
void APIENTRY D3DDisable (GLenum cap){
gFakeGL->cglDisable(cap);
}
void APIENTRY D3DDrawBuffer (GLenum mode){
gFakeGL->cglDrawBuffer(mode);
}
void APIENTRY D3DEnable (GLenum cap){
gFakeGL->cglEnable(cap);
}
void APIENTRY D3DEnd (void){
return; // Does nothing
// gFakeGL->glEnd();
}
void APIENTRY D3DFinish (void){
gFakeGL->cglFinish();
}
void APIENTRY D3DFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar){
gFakeGL->cglFrustum(left, right, bottom, top, zNear, zFar);
}
void APIENTRY D3DGetFloatv (GLenum pname, GLfloat *params){
gFakeGL->cglGetFloatv(pname, params);
}
const GLubyte * APIENTRY D3DGetString (GLenum name){
return gFakeGL->cglGetString(name);
}
void APIENTRY D3DHint (GLenum target, GLenum mode){
gFakeGL->cglHint(target, mode);
}
void APIENTRY D3DLoadIdentity (void){
gFakeGL->cglLoadIdentity();
}
void APIENTRY D3DLoadMatrixf (const GLfloat *m){
gFakeGL->cglLoadMatrixf(m);
}
void APIENTRY D3DMatrixMode (GLenum mode){
gFakeGL->cglMatrixMode(mode);
}
void APIENTRY D3DOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar){
gFakeGL->cglOrtho(left, right, top, bottom, zNear, zFar);
}
void APIENTRY D3DPolygonMode (GLenum face, GLenum mode){
gFakeGL->cglPolygonMode(face, mode);
}
void APIENTRY D3DPopMatrix (void){
gFakeGL->cglPopMatrix();
}
void APIENTRY D3DPushMatrix (void){
gFakeGL->cglPushMatrix();
}
void APIENTRY D3DReadBuffer (GLenum mode){
gFakeGL->cglReadBuffer(mode);
}
void APIENTRY D3DReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels){
gFakeGL->cglReadPixels(x, y, width, height, format, type, pixels);
}
void APIENTRY D3DRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z){
gFakeGL->cglRotatef(angle, x, y, z);
}
void APIENTRY D3DScalef (GLfloat x, GLfloat y, GLfloat z){
gFakeGL->cglScalef(x, y, z);
}
void APIENTRY D3DShadeModel (GLenum mode){
gFakeGL->cglShadeModel(mode);
}
void APIENTRY D3DTexCoord2f (GLfloat s, GLfloat t){
gFakeGL->cglTexCoord2f(s, t);
}
void APIENTRY D3DTexEnvf (GLenum target, GLenum pname, GLfloat param){
gFakeGL->cglTexEnvf(target, pname, param);
}
void APIENTRY D3DTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels){
gFakeGL->cglTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
}
void APIENTRY D3DTexParameterf (GLenum target, GLenum pname, GLfloat param){
gFakeGL->cglTexParameterf(target, pname, param);
}
void APIENTRY D3DTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels){
gFakeGL->cglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
}
void APIENTRY D3DTranslatef (GLfloat x, GLfloat y, GLfloat z){
gFakeGL->cglTranslatef(x, y, z);
}
void APIENTRY D3DVertex2f (GLfloat x, GLfloat y){
gFakeGL->cglVertex2f(x, y);
}
void APIENTRY D3DVertex3f (GLfloat x, GLfloat y, GLfloat z){
gFakeGL->cglVertex3f(x, y, z);
}
void APIENTRY D3DVertex3fv (const GLfloat *v){
gFakeGL->cglVertex3fv(v);
}
void APIENTRY D3DViewport (GLint x, GLint y, GLsizei width, GLsizei height){
gFakeGL->cglViewport(x, y, width, height);
}
int APIENTRY D3DGetError (void)
{
return 0;
}
HDC gHDC;
HGLRC gHGLRC;
extern "C" {
extern HWND mainwindow;
};
HGLRC WINAPI D3DwglCreateContext(HDC /* hdc */){
return (HGLRC) new FakeGL(mainwindow);
}
BOOL WINAPI D3DwglDeleteContext(HGLRC hglrc){
FakeGL* fgl = (FakeGL*) hglrc;
delete fgl;
return true;
}
HGLRC WINAPI D3DwglGetCurrentContext(VOID){
return gHGLRC;
}
HDC WINAPI D3DwglGetCurrentDC(VOID){
return gHDC;
}
static void APIENTRY D3DBindTextureExt(GLenum target, GLuint texture){
gFakeGL->cglBindTexture(target, texture);
}
static void APIENTRY D3DMTexCoord2fSGIS(GLenum target, GLfloat s, GLfloat t){
gFakeGL->cglMTexCoord2fSGIS(target, s, t);
}
static void APIENTRY D3DSelectTextureSGIS(GLenum target){
gFakeGL->cglSelectTextureSGIS(target);
}
// type cast unsafe conversion from
#pragma warning( push )
#pragma warning( disable : 4191)
typedef struct {
char *funcname;
PROC functionp;
} d3dglfunc_t;
extern d3dglfunc_t glfuncs[];
PROC WINAPI D3DwglGetProcAddress(LPCSTR s)
{
int i;
static LPCSTR kBindTextureEXT = "glBindTextureEXT";
static LPCSTR kMTexCoord2fSGIS = "glMTexCoord2fSGIS"; // Multitexture
static LPCSTR kSelectTextureSGIS = "glSelectTextureSGIS";
if ( strcmp(s, kBindTextureEXT) == 0){
return (PROC) D3DBindTextureExt;
}
else if ( strcmp(s, kMTexCoord2fSGIS) == 0){
return (PROC) D3DMTexCoord2fSGIS;
}
else if ( strcmp(s, kSelectTextureSGIS) == 0){
return (PROC) D3DSelectTextureSGIS;
}
for (i = 0; glfuncs[i].funcname; i++)
{
if (!strcmp(s, glfuncs[i].funcname))
return glfuncs[i].functionp;
}
// LocalDebugBreak();
return 0;
}
#pragma warning( pop )
BOOL WINAPI D3DwglMakeCurrent(HDC hdc, HGLRC hglrc){
gHDC = hdc;
gHGLRC = hglrc;
gFakeGL = (FakeGL*) hglrc;
return TRUE;
}
extern "C"{
void d3dSetMode(int fullscreen, int width, int height, int bpp, int zbpp);
void d3dEvictTextures();
BOOL APIENTRY FakeSwapBuffers(HDC hdc);
void d3dSetGammaRamp(const unsigned char* gammaTable);
void d3dInitSetForce16BitTextures(int force16bitTextures);
void d3dHint_GenerateMipMaps(int value);
float d3dGetD3DDriverVersion();
void D3DInitialize(void);
};
void d3dEvictTextures(){
gFakeGL->EvictTextures();
}
void d3dSetMode(int fullscreen, int width, int height, int bpp, int zbpp){
gFullScreen = fullscreen != 0;
gWidth = width;
gHeight = height;
gBpp = bpp;
gZbpp = zbpp;
}
BOOL APIENTRY FakeSwapBuffers(HDC hdc){
if ( ! gFakeGL ) {
return false;
}
gFakeGL->SwapBuffers();
return true;
}
void d3dSetGammaRamp(const unsigned char* gammaTable){
gFakeGL->SetGammaRamp(gammaTable);
}
void d3dInitSetForce16BitTextures(int force16bitTextures){
// called before gFakeGL exits. That's why we set a global
g_force16bitTextures = force16bitTextures != 0;
}
void d3dHint_GenerateMipMaps(int value){
gFakeGL->Hint_GenerateMipMaps(value);
}
float d3dGetD3DDriverVersion(){
return 0.73f;
}
void APIENTRY D3DTexCoord2fv(const GLfloat *f)
{
D3DTexCoord2f(f[0], f[1]);
}
void APIENTRY D3DTexCoord1f(GLfloat f)
{
D3DTexCoord2f(f, f);
}
void APIENTRY D3DTexParameteri (GLenum target, GLenum pname, GLint param)
{
D3DTexParameterf(target, pname, param);
}
void APIENTRY D3DTexEnvi (GLenum target, GLenum pname, GLint param)
{
D3DTexEnvf(target, pname, param);
}
void APIENTRY D3DMultMatrixf (const GLfloat *m)
{
gFakeGL->cglMultMatrixf(m);
}
void APIENTRY D3DNormal3f(GLfloat x, GLfloat y, GLfloat z)
{}
void APIENTRY D3DNormal3fv (const GLfloat *v)
{D3DNormal3f(v[0], v[1], v[2]);}
void APIENTRY D3DFogf (GLenum pname, GLfloat param)
{}
void APIENTRY D3DFogi (GLenum pname, GLint param)
{}
void APIENTRY D3DFogfv (GLenum pname, const GLfloat *params)
{}
void APIENTRY D3DGetIntegerv (GLenum pname, GLint *params)
{
switch(pname)
{
case GL_MAX_TEXTURE_SIZE:
params[0]=2048;
break;
case GL_MAX_TEXTURE_UNITS_ARB:
params[0]=2;
break;
default:
Sys_Error("Bad D3DGetIntegerv\n");
}
}
void APIENTRY D3DNewList (GLuint list, GLenum mode)
{}
void APIENTRY D3DEndList (void)
{}
void APIENTRY D3DCallList (GLuint list)
{}
void APIENTRY D3DTexGeni (GLenum coord, GLenum pname, GLint param)
{}
int texarraystride;
bool texarrayenabled;
const float *texarray;
int vertarraystride;
bool vertarrayenabled;
const float *vertarray;
bool colourarrayenabled;
int colourarraystride;
const qbyte *colourarray;
void APIENTRY D3DDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
{
int *index;
if (!texarrayenabled || !vertarrayenabled)
return; //please explain?
D3DBegin(mode);
if (colourarrayenabled)
{
for (index = (int*)indices; count--; index++)
{
D3DTexCoord2fv(texarray + *index*texarraystride);
D3DColor4ubv(colourarray + *index*colourarraystride);
D3DVertex3fv(vertarray + *index*vertarraystride);
}
}
else
{
for (index = (int*)indices; count--; index++)
{
D3DTexCoord2fv(texarray + *index*texarraystride);
D3DVertex3fv(vertarray + *index*vertarraystride);
}
}
D3DEnd();
}
void APIENTRY D3DVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
vertarray = (float *)pointer;
if (size != 3 || type != GL_FLOAT || (stride%4))
Sys_Error("D3DVertexPointer is limited");
if (!stride)
stride = sizeof(float)*size;
vertarraystride = stride/4;
}
void APIENTRY D3DTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
texarray = (float *)pointer;
if (size != 2 || type != GL_FLOAT || (stride%4))
Sys_Error("D3DTexCoordPointer is limited");
if (!stride)
stride = sizeof(float)*size;
texarraystride = stride/4;
}
void APIENTRY D3DColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
colourarray = (qbyte *)pointer;
if (size != 4 || type != GL_UNSIGNED_BYTE || (stride%4))
Sys_Error("D3DColourPointer is limited");
if (!stride)
stride = sizeof(float)*size;
colourarraystride = stride/4;
}
void APIENTRY D3DEnableClientState(unsigned int e)
{
switch(e)
{
case GL_TEXTURE_COORD_ARRAY:
texarrayenabled = true;
break;
case GL_COLOR_ARRAY:
colourarrayenabled = true;
break;
case GL_VERTEX_ARRAY:
vertarrayenabled = true;
break;
}
}
void APIENTRY D3DDisableClientState(unsigned int e)
{
switch(e)
{
case GL_TEXTURE_COORD_ARRAY:
texarrayenabled = false;
break;
case GL_COLOR_ARRAY:
colourarrayenabled = false;
break;
case GL_VERTEX_ARRAY:
vertarrayenabled = false;
break;
}
}
#if 1
#pragma comment(lib, "../libs/dxsdk7/lib/ddraw.lib")
#pragma comment(lib, "../libs/dxsdk7/lib/d3dx.lib")
#else
HMODULE ddrawdll;
#endif
void D3DInitialize(void)
{
#if 1
qD3DXMatrixScaling = D3DXMatrixScaling;
qD3DXGetErrorString = D3DXGetErrorString;
qD3DXMatrixPerspectiveOffCenter = D3DXMatrixPerspectiveOffCenter;
qD3DXMatrixOrthoOffCenter = D3DXMatrixOrthoOffCenter;
qD3DXInitialize = D3DXInitialize;
qD3DXUninitialize = D3DXUninitialize;
qD3DXCreateContextEx = D3DXCreateContextEx;
qD3DXCreateMatrixStack = D3DXCreateMatrixStack;
qD3DXCheckTextureRequirements = D3DXCheckTextureRequirements;
qD3DXMakeDDPixelFormat = D3DXMakeDDPixelFormat;
qD3DXMatrixTranslation = D3DXMatrixTranslation;
#else
if (!ddrawdll)
ddrawdll = LoadLibrary("d3drm.dll"); //yeah, right, these are staticly linked. DLLS get speed hits.
qD3DXMatrixScaling = (qD3DXMatrixScaling_t) GetProcAddress(ddrawdll, "D3DXMatrixScaling");
qD3DXGetErrorString = (qD3DXGetErrorString_t) GetProcAddress(ddrawdll, "D3DXGetErrorString");
qD3DXMatrixPerspectiveOffCenter = (qD3DXMatrixPerspectiveOffCenter_t) GetProcAddress(ddrawdll, "D3DXMatrixPerspectiveOffCenter");
qD3DXMatrixOrthoOffCenter = (qD3DXMatrixOrthoOffCenter_t) GetProcAddress(ddrawdll, "D3DXMatrixOrthoOffCenter");
qD3DXInitialize = (qD3DXInitialize_t) GetProcAddress(ddrawdll, "D3DXInitialize");
qD3DXUninitialize = (qD3DXUninitialize_t) GetProcAddress(ddrawdll, "D3DXUninitialize");
qD3DXCreateContextEx = (qD3DXCreateContextEx_t) GetProcAddress(ddrawdll, "D3DXCreateContextEx");
qD3DXCreateMatrixStack = (qD3DXCreateMatrixStack_t) GetProcAddress(ddrawdll, "D3DXCreateMatrixStack");
qD3DXCheckTextureRequirements = (qD3DXCheckTextureRequirements_t) GetProcAddress(ddrawdll, "D3DXCheckTextureRequirements");
qD3DXMakeDDPixelFormat = (qD3DXMakeDDPixelFormat_t) GetProcAddress(ddrawdll, "D3DXMakeDDPixelFormat");
qD3DXMatrixTranslation = (qD3DXMatrixTranslation_t) GetProcAddress(ddrawdll, "D3DXMatrixTranslation");
#endif
if (!qD3DXCreateMatrixStack || !qD3DXMatrixScaling || !qD3DXMatrixTranslation || !qD3DXMatrixPerspectiveOffCenter
|| !qD3DXMatrixOrthoOffCenter || !qD3DXGetErrorString || !qD3DXInitialize || !qD3DXUninitialize
|| !qD3DXCreateContextEx || !qD3DXCheckTextureRequirements || !qD3DXMakeDDPixelFormat)
Sys_Error("You don't have directx 7");
/*
qglAlphaFunc = D3DAlphaFunc;
qglBegin = D3DBegin;
qglBlendFunc = D3DBlendFunc;
qglClear = D3DClear;
qglClearColor = D3DClearColor;
qglColor3f = D3DColor3f;
qglColor3ub = D3DColor3ub;
qglColor4f = D3DColor4f;
qglColor4fv = D3DColor4fv;
qglColor4ub = D3DColor4ub;
qglColor4ubv = D3DColor4ubv;
qglCullFace = D3DCullFace;
qglDepthFunc = D3DDepthFunc;
qglDepthMask = D3DDepthMask;
qglDepthRange = D3DDepthRange;
qglDisable = D3DDisable;
qglDrawBuffer = D3DDrawBuffer;
qglEnable = D3DEnable;
qglEnd = D3DEnd;
qglFinish = D3DFinish;
qglFrustum = D3DFrustum;
qglGetFloatv = D3DGetFloatv;
qglGetIntegerv = D3DGetIntegerv;
qglGetString = D3DGetString;
qglHint = D3DHint;
qglLoadIdentity = D3DLoadIdentity;
qglLoadMatrixf = D3DLoadMatrixf;
qglNormal3f = D3DNormal3f;
qglNormal3fv = D3DNormal3fv;
qglMatrixMode = D3DMatrixMode;
qglMultMatrixf = D3DMultMatrixf;
qglOrtho = D3DOrtho;
qglPolygonMode = D3DPolygonMode;
qglPopMatrix = D3DPopMatrix;
qglPushMatrix = D3DPushMatrix;
qglReadBuffer = D3DReadBuffer;
qglReadPixels = D3DReadPixels;
qglRotatef = D3DRotatef;
qglScalef = D3DScalef;
qglShadeModel = D3DShadeModel;
qglTexCoord1f = D3DTexCoord1f;
qglTexCoord2f = D3DTexCoord2f;
qglTexCoord2fv = D3DTexCoord2fv;
qglTexEnvf = D3DTexEnvf;
qglTexEnvi = D3DTexEnvi;
qglTexGeni = D3DTexGeni;
qglTexImage2D = D3DTexImage2D;
qglTexParameteri = D3DTexParameteri;
qglTexParameterf = D3DTexParameterf;
qglTexSubImage2D = D3DTexSubImage2D;
qglTranslatef = D3DTranslatef;
qglVertex2f = D3DVertex2f;
qglVertex3f = D3DVertex3f;
qglVertex3fv = D3DVertex3fv;
qglViewport = D3DViewport;
qglDrawElements = D3DDrawElements;
qglVertexPointer = D3DVertexPointer;
qglTexCoordPointer = D3DTexCoordPointer;
qglEnableClientState = D3DEnableClientState;
qglDisableClientState = D3DDisableClientState;
*/
qwglCreateContext = D3DwglCreateContext;
qwglDeleteContext = D3DwglDeleteContext;
qwglGetCurrentContext = D3DwglGetCurrentContext;
qwglGetCurrentDC = D3DwglGetCurrentDC;
qwglGetProcAddress = D3DwglGetProcAddress;
qwglMakeCurrent = D3DwglMakeCurrent;
qSwapBuffers = FakeSwapBuffers;
}
d3dglfunc_t glfuncs[] = {
{"glAlphaFunc", (PROC)D3DAlphaFunc},
{"glBegin", (PROC)D3DBegin},
{"glBlendFunc", (PROC)D3DBlendFunc},
{"glClear", (PROC)D3DClear},
{"glClearColor", (PROC)D3DClearColor},
{"glClearDepth", NULL},
{"glClearStencil", NULL},
{"glColor3f", (PROC)D3DColor3f},
{"glColor3ub", (PROC)D3DColor3ub},
{"glColor4f", (PROC)D3DColor4f},
{"glColor4fv", (PROC)D3DColor4fv},
{"glColor4ub", (PROC)D3DColor4ub},
{"glColor4ubv", (PROC)D3DColor4ubv},
{"glColorMask", NULL},//(PROC)D3DColorMask},
{"glCullFace", (PROC)D3DCullFace},
{"glDepthFunc", (PROC)D3DDepthFunc},
{"glDepthMask", (PROC)D3DDepthMask},
{"glDepthRange", (PROC)D3DDepthRange},
{"glDisable", (PROC)D3DDisable},
{"glDrawBuffer", (PROC)D3DDrawBuffer},
{"glDrawPixels", NULL},//(PROC)D3DDrawPixels},
{"glEnable", (PROC)D3DEnable},
{"glEnd", (PROC)D3DEnd},
{"glFlush", NULL},//(PROC)D3DFlush},
{"glFinish", (PROC)D3DFinish},
{"glFrustum", (PROC)D3DFrustum},
{"glGetFloatv", (PROC)D3DGetFloatv},
{"glGetIntegerv", (PROC)D3DGetIntegerv},
{"glGetString", (PROC)D3DGetString},
{"glHint", (PROC)D3DHint},
{"glLoadIdentity", (PROC)D3DLoadIdentity},
{"glLoadMatrixf", (PROC)D3DLoadMatrixf},
{"glNormal3f", (PROC)D3DNormal3f},
{"glNormal3fv", (PROC)D3DNormal3fv},
{"glMatrixMode", (PROC)D3DMatrixMode},
{"glMultMatrixf", (PROC)D3DMultMatrixf},
{"glOrtho", (PROC)D3DOrtho},
{"glPolygonMode", (PROC)D3DPolygonMode},
{"glPopMatrix", (PROC)D3DPopMatrix},
{"glPushMatrix", (PROC)D3DPushMatrix},
{"glReadBuffer", (PROC)D3DReadBuffer},
{"glReadPixels", (PROC)D3DReadPixels},
{"glRotatef", (PROC)D3DRotatef},
{"glScalef", (PROC)D3DScalef},
{"glShadeModel", (PROC)D3DShadeModel},
{"glTexCoord1f", (PROC)D3DTexCoord1f},
{"glTexCoord2f", (PROC)D3DTexCoord2f},
{"glTexCoord2fv", (PROC)D3DTexCoord2fv},
{"glTexEnvf", (PROC)D3DTexEnvf},
{"glTexEnvi", (PROC)D3DTexEnvi},
{"glTexGeni", (PROC)D3DTexGeni},
{"glTexImage2D", (PROC)D3DTexImage2D},
{"glTexParameteri", (PROC)D3DTexParameteri},
{"glTexParameterf", (PROC)D3DTexParameterf},
{"glTexSubImage2D", (PROC)D3DTexSubImage2D},
{"glTranslatef", (PROC)D3DTranslatef},
{"glVertex2f", (PROC)D3DVertex2f},
{"glVertex3f", (PROC)D3DVertex3f},
{"glVertex3fv", (PROC)D3DVertex3fv},
{"glViewport", (PROC)D3DViewport},
{"glDrawElements", (PROC)D3DDrawElements},
{"glVertexPointer", (PROC)D3DVertexPointer},
{"glTexCoordPointer", (PROC)D3DTexCoordPointer},
{"glColorPointer", (PROC)D3DColorPointer},
{"glEnableClientState", (PROC)D3DEnableClientState},
{"glDisableClientState", (PROC)D3DDisableClientState},
{"glGetError", (PROC)D3DGetError},
/*
qwglCreateContext = D3DwglCreateContext;
qwglDeleteContext = D3DwglDeleteContext;
qwglGetCurrentContext = D3DwglGetCurrentContext;
qwglGetCurrentDC = D3DwglGetCurrentDC;
qwglGetProcAddress = D3DwglGetProcAddress;
qwglMakeCurrent = D3DwglMakeCurrent;
qSwapBuffers = FakeSwapBuffers;*/
{NULL}
};
qboolean D3DVID_Init(rendererstate_t *info, unsigned char *palette)
{
strcpy(info->glrenderer, "D3D");
return GLVID_Init(info, palette);
}
extern "C" {
#include "gl_draw.h"
}
rendererinfo_t d3drendererinfo = {
"Direct3D",
{
"faked3d",
"crap"
},
QR_OPENGL,
GLDraw_SafePicFromWad,
GLDraw_CachePic,
GLDraw_SafeCachePic,
GLDraw_Init,
GLDraw_ReInit,
GLDraw_Character,
GLDraw_ColouredCharacter,
GLDraw_TinyCharacter,
GLDraw_String,
GLDraw_Alt_String,
GLDraw_Crosshair,
GLDraw_DebugChar,
GLDraw_Pic,
GLDraw_ScalePic,
GLDraw_SubPic,
GLDraw_TransPic,
GLDraw_TransPicTranslate,
GLDraw_ConsoleBackground,
GLDraw_EditorBackground,
GLDraw_TileClear,
GLDraw_Fill,
GLDraw_FillRGB,
GLDraw_FadeScreen,
GLDraw_BeginDisc,
GLDraw_EndDisc,
GLDraw_Image,
GLDraw_ImageColours,
GLR_Init,
GLR_DeInit,
GLR_ReInit,
GLR_RenderView,
NULL,
NULL,
GLR_NewMap,
GLR_PreNewMap,
GLR_LightPoint,
GLR_PushDlights,
Surf_AddStain,
Surf_LessenStains,
MediaGL_ShowFrameBGR_24_Flip,
MediaGL_ShowFrameRGBA_32,
MediaGL_ShowFrame8bit,
GLMod_Init,
GLMod_ClearAll,
GLMod_ForName,
GLMod_FindName,
GLMod_Extradata,
GLMod_TouchModel,
GLMod_NowLoadExternal,
GLMod_Think,
Mod_GetTag,
Mod_TagNumForName,
Mod_SkinForName,
Mod_FrameForName,
Mod_GetFrameDuration,
D3DVID_Init,
GLVID_DeInit,
GLVID_LockBuffer,
GLVID_UnlockBuffer,
GLD_BeginDirectRect,
GLD_EndDirectRect,
GLVID_ForceLockState,
GLVID_ForceUnlockedAndReturnState,
GLVID_SetPalette,
GLVID_ShiftPalette,
GLVID_GetRGBInfo,
NULL, //setcaption
GLSCR_UpdateScreen,
""
};
extern "C" {
rendererinfo_t *pd3drendererinfo = &d3drendererinfo;
}
#endif
#endif