1f9484f93d
Wonder how much this breaks. Place your bets now. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2501 fc73d0e0-1445-4013-8a0c-d673dee63da5
4174 lines
111 KiB
C++
4174 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_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,
|
|
|
|
|
|
GLR_CheckSky,
|
|
GLR_SetSky,
|
|
|
|
GLR_NewMap,
|
|
GLR_PreNewMap,
|
|
GLR_LightPoint,
|
|
GLR_PushDlights,
|
|
|
|
|
|
GLR_AddStain,
|
|
GLR_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,
|
|
NULL,
|
|
|
|
D3DVID_Init,
|
|
GLVID_DeInit,
|
|
GLVID_HandlePause,
|
|
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
|
|
|