1
0
forked from 0ad/0ad

Changed terrain stuff from ScEd 0.0.5.2

This was SVN commit r203.
This commit is contained in:
Simon Brenner 2004-04-13 16:54:34 +00:00
parent 0cd2d55569
commit d4ca9695d7
26 changed files with 1159 additions and 734 deletions

View File

@ -10,6 +10,7 @@
//----------------------------------------------------------- //-----------------------------------------------------------
// necessary includes // necessary includes
#include <assert.h>
#include <float.h> #include <float.h>
#include "Bound.h" #include "Bound.h"
@ -138,3 +139,27 @@ void CBound::SetEmpty()
} }
void CBound::Transform(const CMatrix3D& m,CBound& result) const
{
assert(this!=&result);
for (int i=0;i<3;++i) {
// handle translation
result[0][i]=result[1][i]=m(3,i);
// Now find the extreme points by considering the product of the
// min and max with each component of matrix
for(int j=0;j<3;j++) {
float a=m(i,j)*m_Data[0][j];
float b=m(i,j)*m_Data[1][j];
if (a<b) {
result[0][i]+=a;
result[1][i]+=b;
} else {
result[0][i]+=b;
result[1][i]+=a;
}
}
}
}

View File

@ -14,6 +14,7 @@
// necessary includes // necessary includes
#include "Vector3D.h" #include "Vector3D.h"
#include "Matrix3D.h"
class CBound class CBound
{ {
@ -22,6 +23,8 @@ public:
CBound(const CVector3D& min,const CVector3D& max) { CBound(const CVector3D& min,const CVector3D& max) {
m_Data[0]=min; m_Data[1]=max; m_Data[0]=min; m_Data[1]=max;
} }
void Transform(const CMatrix3D& m,CBound& result) const;
CVector3D& operator[](int index) { return m_Data[index]; } CVector3D& operator[](int index) { return m_Data[index]; }
const CVector3D& operator[](int index) const { return m_Data[index]; } const CVector3D& operator[](int index) const { return m_Data[index]; }

View File

@ -26,21 +26,21 @@ CCamera::CCamera ()
CCamera::~CCamera () CCamera::~CCamera ()
{ {
} }
void CCamera::SetProjection (float nearp, float farp, float fov) void CCamera::SetProjection (float nearp, float farp, float fov)
{ {
float h, w, Q; float h, w, Q;
m_NearPlane = nearp; m_NearPlane = nearp;
m_FarPlane = farp; m_FarPlane = farp;
m_FOV = fov; m_FOV = fov;
float Aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height; float Aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
w = 1/tanf (fov*0.5f*Aspect); w = 1/tanf (fov*0.5f*Aspect);
h = 1/tanf (fov*0.5f); h = 1/tanf (fov*0.5f);
Q = m_FarPlane / (m_FarPlane - m_NearPlane); Q = m_FarPlane / (m_FarPlane - m_NearPlane);
m_ProjMat.SetZero (); m_ProjMat.SetZero ();
m_ProjMat._11 = w; m_ProjMat._11 = w;
m_ProjMat._22 = h; m_ProjMat._22 = h;
@ -57,8 +57,8 @@ void CCamera::UpdateFrustum ()
CMatrix3D MatFinal; CMatrix3D MatFinal;
CMatrix3D MatView; CMatrix3D MatView;
MatView = m_Orientation.GetTranspose (); m_Orientation.Invert(MatView);
MatFinal = m_ProjMat * MatView; MatFinal = m_ProjMat * MatView;
//get the RIGHT plane //get the RIGHT plane

View File

@ -69,4 +69,4 @@ class CCamera
CFrustum m_ViewFrustum; CFrustum m_ViewFrustum;
}; };
#endif #endif

View File

@ -12,12 +12,13 @@
#ifndef MATHUTIL_H #ifndef MATHUTIL_H
#define MATHUTIL_H #define MATHUTIL_H
#ifndef PI
#define PI 3.14159265358979323846f #define PI 3.14159265358979323846f
#endif
#define DEGTORAD(a) ((a) * (PI/180.0f)) #define DEGTORAD(a) ((a) * (PI/180.0f))
#define RADTODEG(a) ((a) * (180.0f/PI)) #define RADTODEG(a) ((a) * (180.0f/PI))
#define SQR(x) ((x) * (x)) #define SQR(x) ((x) * (x))
#define MAX3(a,b,c) ( MAX (MAX(a,b), c) ) #define MAX3(a,b,c) ( MAX (MAX(a,b), c) )
#define ABS(a) ((a > 0) ? (a) : (-a)) #define ABS(a) ((a > 0) ? (a) : (-a))

View File

@ -277,36 +277,27 @@ void CMatrix3D::Scale (float x_scale, float y_scale, float z_scale)
//Returns the transpose of the matrix. For orthonormal //Returns the transpose of the matrix. For orthonormal
//matrices, this is the same is the inverse matrix //matrices, this is the same is the inverse matrix
CMatrix3D CMatrix3D::GetTranspose() const void CMatrix3D::GetTranspose(CMatrix3D& result) const
{ {
CMatrix3D Temp; result._11 = _11;
result._21 = _12;
result._31 = _13;
result._41 = _14;
Temp._11 = _11; result._12 = _21;
Temp._21 = _12; result._22 = _22;
Temp._31 = _13; result._32 = _23;
Temp._41 = 0.0f; result._42 = _24;
Temp._12 = _21; result._13 = _31;
Temp._22 = _22; result._23 = _32;
Temp._32 = _23; result._33 = _33;
Temp._42 = 0.0f; result._43 = _34;
Temp._13 = _31; result._14 = _41;
Temp._23 = _32; result._24 = _42;
Temp._33 = _33; result._34 = _43;
Temp._43 = 0.0f; result._44 = _44;
Temp._14 = 0.0f;
Temp._24 = 0.0f;
Temp._34 = 0.0f;
Temp._44 = 1.0f;
CMatrix3D Trans;
Trans.SetTranslation (-_14, -_24, -_34);
Temp = Temp * Trans;
return Temp;
} }
//Get a vector which points to the left of the matrix //Get a vector which points to the left of the matrix

View File

@ -84,7 +84,7 @@ class CMatrix3D
//Returns the transpose of the matrix. For orthonormal //Returns the transpose of the matrix. For orthonormal
//matrices, this is the same is the inverse matrix //matrices, this is the same is the inverse matrix
CMatrix3D GetTranspose() const; void GetTranspose(CMatrix3D& result) const;
//Get a vector which points to the left of the matrix //Get a vector which points to the left of the matrix
CVector3D GetLeft () const; CVector3D GetLeft () const;

View File

@ -1,22 +1,21 @@
#include "MiniPatch.h" #include "MiniPatch.h"
#include "Patch.h"
CMiniPatch::CMiniPatch() CMiniPatch::CMiniPatch()
{ {
Tex1 = Tex2 = 0; Tex1 = 0;
m_AlphaMap = 0; Tex1Priority = 0;
m_pRightNeighbor = NULL; m_Parent = NULL;
m_pParrent = NULL;
m_Rotation = 0;
m_RenderStage = 0;
m_LastRenderedFrame = 0;
} }
CMiniPatch::~CMiniPatch() CMiniPatch::~CMiniPatch()
{ {
} }
void CMiniPatch::Initialize (STerrainVertex *first_vertex) void CMiniPatch::GetTileIndex(u32& x,u32& z)
{ {
m_pVertices = first_vertex; u32 tindex=this-&m_Parent->m_MiniPatches[0][0];
x=(m_Parent->m_X*16)+tindex%16;
z=(m_Parent->m_Z*16)+tindex/16;
}
}

View File

@ -2,36 +2,28 @@
#define MINIPATCH_H #define MINIPATCH_H
#include "res/res.h" #include "res/res.h"
#include "Color.h"
#include "Vector3D.h"
struct STerrainVertex
{
CVector3D m_Position;
CVector3D m_Normal;
RGBColor m_Color;
};
class CPatch;
class CMiniPatch class CMiniPatch
{ {
public: public:
CMiniPatch(); CMiniPatch();
~CMiniPatch(); ~CMiniPatch();
void Initialize (STerrainVertex *first_vertex); // get the index of this tile in the root terrain object; x,y in [0,MapSize)
void GetTileIndex(u32& x,u32& z);
Handle Tex1;
int Tex1Priority;
// Handle Tex2;
// Handle m_AlphaMap;
// unsigned int m_AlphaMapFlags;
Handle Tex1, Tex2; CPatch *m_Parent;
Handle m_AlphaMap; // STerrainVertex *m_pVertices;
CMiniPatch *m_pRightNeighbor;
CPatch *m_pParrent;
unsigned char m_RenderStage;
unsigned int m_LastRenderedFrame;
unsigned char m_Rotation;
STerrainVertex *m_pVertices;
}; };
#endif #endif

View File

@ -11,11 +11,13 @@
#include "Model.h" #include "Model.h"
#include "Quaternion.h" #include "Quaternion.h"
#include "Bound.h"
CModel::CModel() CModel::CModel()
{ {
m_pModelDef = NULL; m_pModelDef = NULL;
m_pBonePoses = NULL; m_pBonePoses = NULL;
m_RenderData = 0;
} }
CModel::~CModel() CModel::~CModel()
@ -126,3 +128,19 @@ void RotateX (CMatrix3D *mat, float angle1, float angle2, float factor)
*mat = RotX * (*mat); *mat = RotX * (*mat);
} }
void CModel::CalcBounds(CBound& bound)
{
bound.SetEmpty();
for (int i=0; i<m_pModelDef->GetNumVertices(); i++)
{
SModelVertex *pVertex = &m_pModelDef->GetVertices()[i];
CVector3D coord;
if (pVertex->m_Bone!=-1) {
bound+=GetBonePoses()[pVertex->m_Bone].Transform(pVertex->m_Coords);
} else {
bound+=pVertex->m_Coords;
}
}
}

View File

@ -14,8 +14,12 @@
#include "Texture.h" #include "Texture.h"
#include "ModelDef.h" #include "ModelDef.h"
#include "RenderableObject.h"
class CModel
class CBound;
class CModel
{ {
public: public:
CModel(); CModel();
@ -27,6 +31,10 @@ class CModel
void SetPose (const char *anim_name, float time); void SetPose (const char *anim_name, float time);
void ClearPose (); void ClearPose ();
void CalcBounds(CBound& bound);
CRenderData* m_RenderData;
//access functions //access functions
public: public:
CModelDef *GetModelDef() { return m_pModelDef; } CModelDef *GetModelDef() { return m_pModelDef; }

View File

@ -94,16 +94,19 @@ void CModelDef::SetupBones()
for (i=0; i<m_NumVertices; i++) for (i=0; i<m_NumVertices; i++)
{ {
SModelVertex *pVertex = &m_pVertices[i]; SModelVertex *pVertex = &m_pVertices[i];
SModelBone *pBone = &m_pBones[pVertex->m_Bone]; if (pVertex->m_Bone>=0) {
SModelBone *pBone = &m_pBones[pVertex->m_Bone];
CVector3D BonePos = pBone->m_Absolute.GetTranslation(); CVector3D BonePos = pBone->m_Absolute.GetTranslation();
pVertex->m_Coords.X -= BonePos.X; pVertex->m_Coords.X -= BonePos.X;
pVertex->m_Coords.Y -= BonePos.Y; pVertex->m_Coords.Y -= BonePos.Y;
pVertex->m_Coords.Z -= BonePos.Z; pVertex->m_Coords.Z -= BonePos.Z;
CMatrix3D BoneInvMat = pBone->m_Absolute.GetTranspose(); CMatrix3D BoneInvMat;
pBone->m_Absolute.Invert(BoneInvMat);
pVertex->m_Coords = BoneInvMat.Rotate (pVertex->m_Coords); pVertex->m_Coords = BoneInvMat.Rotate (pVertex->m_Coords);
}
} }
} }

View File

@ -99,7 +99,7 @@ class CModelDef
int GetNumAnimationFrames() { return m_NumAnimationFrames; } int GetNumAnimationFrames() { return m_NumAnimationFrames; }
int GetNumAnimations() { return m_NumAnimations; } int GetNumAnimations() { return m_NumAnimations; }
protected: public:
SModelVertex *m_pVertices; SModelVertex *m_pVertices;
SModelFace *m_pFaces; SModelFace *m_pFaces;
SModelBone *m_pBones; SModelBone *m_pBones;

View File

@ -11,40 +11,51 @@
//*********************************************************** //***********************************************************
#include "Patch.h" #include "Patch.h"
#include "Terrain.h"
CPatch::CPatch () CPatch::CPatch()
{ {
m_pVertices = NULL; m_Parent = NULL;
} }
CPatch::~CPatch () CPatch::~CPatch()
{ {
} }
//Initialize the patch void CPatch::Initialize(CTerrain* parent,u32 x,u32 z)
void CPatch::Initialize (STerrainVertex *first_vertex)
{ {
int j; delete m_RenderData;
m_RenderData;
m_pVertices = first_vertex; m_Parent=parent;
m_X=x;
m_Z=z;
u32 mapSize=m_Parent->GetVerticesPerSide();
for (int j=0; j<16; j++) {
for (int i=0; i<16; i++) {
m_MiniPatches[j][i].m_Parent=this;
}
}
CalcBounds();
}
void CPatch::CalcBounds()
{
u32 mapSize=m_Parent->GetVerticesPerSide();
m_Bounds.SetEmpty(); m_Bounds.SetEmpty();
for (j=0; j<PATCH_SIZE+1; j++) for (int j=0; j<PATCH_SIZE+1; j++)
{ {
for (int i=0; i<PATCH_SIZE+1; i++) for (int i=0; i<PATCH_SIZE+1; i++)
{ {
m_Bounds+=m_pVertices[j*MAP_SIZE + i].m_Position; CVector3D pos;
} m_Parent->CalcPosition(m_X*PATCH_SIZE+i,m_Z*PATCH_SIZE+j,pos);
} m_Bounds+=pos;
for (j=0; j<16; j++)
{
for (int i=0; i<16; i++)
{
int pos = (j*MAP_SIZE) + (i);
m_MiniPatches[j][i].Initialize ( &m_pVertices[pos] );
} }
} }
} }

View File

@ -12,27 +12,32 @@
#ifndef PATCH_H #ifndef PATCH_H
#define PATCH_H #define PATCH_H
#include "Bound.h" #include "Matrix3D.h"
#include "Camera.h"
#include "TerrGlobals.h" #include "TerrGlobals.h"
#include "MiniPatch.h" #include "MiniPatch.h"
#include "RenderableObject.h"
class CPatch
class CPatch : public CRenderableObject
{ {
public: public:
CPatch (); CPatch();
~CPatch (); ~CPatch();
//initialize the patch //initialize the patch
void Initialize (STerrainVertex *first_vertex); void Initialize(CTerrain* parent,u32 x,u32 z);
// protected: // calculate and store bounds of this patch
CMiniPatch m_MiniPatches[16][16]; void CalcBounds();
CBound m_Bounds; // minipatches (tiles) making up the patch
unsigned int m_LastVisFrame; CMiniPatch m_MiniPatches[16][16];
// position of patch in parent terrain grid
STerrainVertex *m_pVertices; u32 m_X,m_Z;
// parent terrain
CTerrain* m_Parent;
}; };
#endif #endif

View File

@ -106,7 +106,7 @@ void CPatchRData::BuildBlends()
} }
} }
if (neighbourTextures.size()>0) { if (neighbourTextures.size()>0) {
u32 count=neighbourTextures.size(); size_t count=neighbourTextures.size();
// sort textures from lowest to highest priority // sort textures from lowest to highest priority
std::sort(neighbourTextures.begin(),neighbourTextures.end()); std::sort(neighbourTextures.begin(),neighbourTextures.end());
@ -175,7 +175,7 @@ void CPatchRData::BuildBlends()
int vsize=PATCH_SIZE+1; int vsize=PATCH_SIZE+1;
SBlendVertex dst; SBlendVertex dst;
int vindex=m_BlendVertices.size(); size_t vindex=m_BlendVertices.size();
const SBaseVertex& vtx0=m_Vertices[(j*vsize)+i]; const SBaseVertex& vtx0=m_Vertices[(j*vsize)+i];
dst.m_UVs[0]=i*0.125f; dst.m_UVs[0]=i*0.125f;

View File

@ -10,21 +10,90 @@
// types - terrain, models, sprites, particles etc // types - terrain, models, sprites, particles etc
//---------------------------------------------------------------- //----------------------------------------------------------------
#include <map>
#include <set>
#include <algorithm>
#include "Renderer.h" #include "Renderer.h"
#include "TransparencyRenderer.h"
#include "Terrain.h" #include "Terrain.h"
#include "Matrix3D.h" #include "Matrix3D.h"
#include "Camera.h" #include "Camera.h"
#include "PatchRData.h"
#include "Texture.h" #include "Texture.h"
#include "LightEnv.h"
#include "Visual.h"
#include "Model.h" #include "Model.h"
#include "ModelDef.h" #include "ModelDef.h"
#include "types.h" #include "types.h"
#include "ogl.h" #include "ogl.h"
#include "res/res.h" #include "res/mem.h"
#include "res/tex.h"
struct TGAHeader {
// header stuff
unsigned char iif_size;
unsigned char cmap_type;
unsigned char image_type;
unsigned char pad[5];
// origin : unused
unsigned short d_x_origin;
unsigned short d_y_origin;
// dimensions
unsigned short width;
unsigned short height;
// bits per pixel : 16, 24 or 32
unsigned char bpp;
// image descriptor : Bits 3-0: size of alpha channel
// Bit 4: must be 0 (reserved)
// Bit 5: should be 0 (origin)
// Bits 6-7: should be 0 (interleaving)
unsigned char image_descriptor;
};
static bool saveTGA(const char* filename,int width,int height,unsigned char* data)
{
FILE* fp=fopen(filename,"wb");
if (!fp) return false;
// fill file header
TGAHeader header;
header.iif_size=0;
header.cmap_type=0;
header.image_type=2;
memset(header.pad,0,sizeof(header.pad));
header.d_x_origin=0;
header.d_y_origin=0;
header.width=width;
header.height=height;
header.bpp=24;
header.image_descriptor=0;
if (fwrite(&header,sizeof(TGAHeader),1,fp)!=1) {
fclose(fp);
return false;
}
// write data
if (fwrite(data,width*height*3,1,fp)!=1) {
fclose(fp);
return false;
}
// return success ..
fclose(fp);
return true;
}
extern CTerrain g_Terrain;
#define RENDER_STAGE_BASE (1)
#define RENDER_STAGE_TRANS (2)
CRenderer::CRenderer () CRenderer::CRenderer ()
{ {
@ -32,7 +101,8 @@ CRenderer::CRenderer ()
m_Height=0; m_Height=0;
m_Depth=0; m_Depth=0;
m_FrameCounter=0; m_FrameCounter=0;
m_TerrainMode=FILL; m_TerrainRenderMode=SOLID;
m_ModelRenderMode=SOLID;
} }
CRenderer::~CRenderer () CRenderer::~CRenderer ()
@ -40,18 +110,38 @@ CRenderer::~CRenderer ()
} }
// EnumCaps: build card cap bits
void CRenderer::EnumCaps()
{
// assume support for nothing
m_Caps.m_VBO=false;
#if 1
// now start querying extensions
if (oglExtAvail("GL_ARB_vertex_buffer_object")) {
m_Caps.m_VBO=true;
}
#endif
}
bool CRenderer::Open(int width, int height, int depth) bool CRenderer::Open(int width, int height, int depth)
{ {
m_Width = width; m_Width = width;
m_Height = height; m_Height = height;
m_Depth = depth; m_Depth = depth;
// set packing parameters
glPixelStorei(GL_PACK_ALIGNMENT,1);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
// setup default state // setup default state
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glClearColor(0.0f,0.0f,0.0f,0.0f); glClearColor(0.0f,0.0f,0.0f,0.0f);
// query card capabilities
EnumCaps();
return true; return true;
} }
@ -72,35 +162,199 @@ void CRenderer::BeginFrame()
// bump frame counter // bump frame counter
m_FrameCounter++; m_FrameCounter++;
// zero out all the per-frame stats
m_Stats.Reset();
// calculate coefficients for terrain and unit lighting
m_SHCoeffsUnits.Clear();
m_SHCoeffsTerrain.Clear();
if (m_LightEnv) {
CVector3D dirlight;
m_LightEnv->GetSunDirection(dirlight);
m_SHCoeffsUnits.AddDirectionalLight(dirlight,m_LightEnv->m_SunColor);
m_SHCoeffsTerrain.AddDirectionalLight(dirlight,m_LightEnv->m_SunColor);
m_SHCoeffsUnits.AddAmbientLight(m_LightEnv->m_UnitsAmbientColor);
m_SHCoeffsTerrain.AddAmbientLight(m_LightEnv->m_TerrainAmbientColor);
}
// clear buffers // clear buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} }
void CRenderer::RenderPatches()
{
// switch on wireframe if we need it
if (m_TerrainRenderMode==WIREFRAME) {
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
// render all the patches, including blend pass
RenderPatchSubmissions();
if (m_TerrainRenderMode==WIREFRAME) {
// switch wireframe off again
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} else if (m_TerrainRenderMode==EDGED_FACES) {
// edged faces: need to make a second pass over the data:
// first switch on wireframe
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
// setup some renderstate ..
glDepthMask(0);
SetTexture(0,0);
glColor4f(1,1,1,0.35f);
glLineWidth(2.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// .. and some client states
glEnableClientState(GL_VERTEX_ARRAY);
uint i;
// render each patch in wireframe
for (i=0;i<m_TerrainPatches.size();++i) {
CPatch* patch=m_TerrainPatches[i].m_Object;
CPatchRData* patchdata=(CPatchRData*) patch->m_RenderData;
patchdata->RenderWireframe();
}
// set color for outline
glColor3f(0,0,1);
glLineWidth(4.0f);
// render outline of each patch
for (i=0;i<m_TerrainPatches.size();++i) {
CPatch* patch=m_TerrainPatches[i].m_Object;
CPatchRData* patchdata=(CPatchRData*) patch->m_RenderData;
patchdata->RenderOutline();
}
// .. and switch off the client states
glDisableClientState(GL_VERTEX_ARRAY);
// .. and restore the renderstates
glDisable(GL_BLEND);
glDepthMask(1);
// restore fill mode, and we're done
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
}
}
void CRenderer::RenderModelSubmissions()
{
uint i;
// first ensure all patches have up to date renderdata built for them; build up transparent passes
// along the way
for (i=0;i<m_Models.size();++i) {
CVisual* visual=m_Models[i].m_Object;
CModelRData* data=(CModelRData*) visual->m_Model->m_RenderData;
if (data==0) {
// no renderdata for model, create it now
data=new CModelRData(visual->m_Model);
} else {
data->Update();
}
BuildTransparentPasses(visual);
}
// setup texture environment to modulate diffuse color with texture color
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
// just pass through texture's alpha
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
// setup client states
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// render models
for (i=0;i<m_Models.size();++i) {
CVisual* visual=m_Models[i].m_Object;
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData;
modeldata->Render(visual->GetTransform());
}
// switch off client states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void CRenderer::RenderModels()
{
// switch on wireframe if we need it
if (m_ModelRenderMode==WIREFRAME) {
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
// render all the models
RenderModelSubmissions();
if (m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} else if (m_ModelRenderMode==EDGED_FACES) {
// edged faces: need to make a second pass over the data:
// first switch on wireframe
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
// setup some renderstate ..
glDepthMask(0);
SetTexture(0,0);
glColor4f(1,1,1,0.75f);
glLineWidth(1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// .. and some client states
glEnableClientState(GL_VERTEX_ARRAY);
// render each model
for (uint i=0;i<m_Models.size();++i) {
CVisual* visual=m_Models[i].m_Object;
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData;
modeldata->RenderWireframe(visual->GetTransform());
}
// .. and switch off the client states
glDisableClientState(GL_VERTEX_ARRAY);
// .. and restore the renderstates
glDisable(GL_BLEND);
glDepthMask(1);
// restore fill mode, and we're done
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
}
}
// force rendering of any batched objects // force rendering of any batched objects
void CRenderer::FlushFrame() void CRenderer::FlushFrame()
{ {
unsigned i; // render submitted patches and models
RenderPatches();
// render base terrain RenderModels();
if (m_TerrainMode==WIREFRAME) {
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
for (i=0;i<m_TerrainPatches.size();++i) { // call on the transparency renderer to render all the transparent stuff
RenderPatchBase(m_TerrainPatches[i].m_Object); g_TransparencyRenderer.Render();
}
for (i=0;i<m_TerrainPatches.size();++i) {
RenderPatchTrans(m_TerrainPatches[i].m_Object);
}
if (m_TerrainMode==WIREFRAME) {
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
}
// render models
for (i=0;i<m_Models.size();++i) {
RenderModel(m_Models[i]);
}
// empty lists // empty lists
m_TerrainPatches.clear(); m_TerrainPatches.clear();
@ -115,7 +369,8 @@ void CRenderer::EndFrame()
void CRenderer::SetCamera(CCamera& camera) void CRenderer::SetCamera(CCamera& camera)
{ {
CMatrix3D view = camera.m_Orientation.GetTranspose(); CMatrix3D view;
camera.m_Orientation.Invert(view);
CMatrix3D proj = camera.GetProjection(); CMatrix3D proj = camera.GetProjection();
float gl_view[16] = {view._11, view._21, view._31, view._41, float gl_view[16] = {view._11, view._21, view._31, view._41,
@ -137,21 +392,21 @@ void CRenderer::SetCamera(CCamera& camera)
const SViewPort& vp = camera.GetViewPort(); const SViewPort& vp = camera.GetViewPort();
glViewport (vp.m_X, vp.m_Y, vp.m_Width, vp.m_Height); glViewport (vp.m_X, vp.m_Y, vp.m_Width, vp.m_Height);
m_Camera=camera;
} }
void CRenderer::Submit(CPatch* patch) void CRenderer::Submit(CPatch* patch)
{ {
SSubmission<CPatch*> sub; SSubmission<CPatch*> sub;
patch->m_LastVisFrame=m_FrameCounter;
sub.m_Object=patch; sub.m_Object=patch;
m_TerrainPatches.push_back(sub); m_TerrainPatches.push_back(sub);
} }
void CRenderer::Submit(CModel* model,CMatrix3D* transform) void CRenderer::Submit(CVisual* visual)
{ {
SSubmission<CModel*> sub; SSubmission<CVisual*> sub;
sub.m_Object=model; sub.m_Object=visual;
sub.m_Transform=transform;
m_Models.push_back(sub); m_Models.push_back(sub);
} }
@ -167,74 +422,109 @@ void CRenderer::Submit(COverlay* overlay)
{ {
} }
void CRenderer::RenderPatchSubmissions()
/*
void CRenderer::RenderTileOutline (CMiniPatch *mpatch)
{ {
glActiveTexture (GL_TEXTURE0); uint i;
glDisable (GL_DEPTH_TEST); // first ensure all patches have up to date renderdata built for them
glDisable (GL_TEXTURE_2D); for (i=0;i<m_TerrainPatches.size();++i) {
glLineWidth (4); CPatch* patch=m_TerrainPatches[i].m_Object;
CPatchRData* data=(CPatchRData*) patch->m_RenderData;
STerrainVertex V[4]; if (data==0) {
V[0] = mpatch->m_pVertices[0]; // no renderdata for patch, create it now
V[1] = mpatch->m_pVertices[1]; data=new CPatchRData(patch);
V[2] = mpatch->m_pVertices[MAP_SIZE*1 + 1]; } else {
V[3] = mpatch->m_pVertices[MAP_SIZE*1]; data->Update();
glColor3f (0,1.0f,0);
glBegin (GL_LINE_LOOP);
for(int i = 0; i < 4; i++)
glVertex3fv(&V[i].m_Position.X);
glEnd ();
glEnable (GL_DEPTH_TEST);
glEnable (GL_TEXTURE_2D);
}
*/
void CRenderer::RenderModel(SSubmission<CModel*>& modelsub)
{
glPushMatrix();
glMultMatrixf(modelsub.m_Transform->_data);
SetTexture(0,modelsub.m_Object->GetTexture());
glColor3f(1.0f,1.0f,1.0f);
CModel* mdl=(CModel*) modelsub.m_Object;
CModelDef* mdldef=(CModelDef*) mdl->GetModelDef();
glBegin(GL_TRIANGLES);
for (int fi=0; fi<mdldef->GetNumFaces(); fi++)
{
SModelFace *pFace = &mdldef->GetFaces()[fi];
for (int vi=0; vi<3; vi++)
{
SModelVertex *pVertex = &mdldef->GetVertices()[pFace->m_Verts[vi]];
CVector3D Coord = mdl->GetBonePoses()[pVertex->m_Bone].Transform(pVertex->m_Coords);
glTexCoord2f (pVertex->m_U, pVertex->m_V);
glVertex3f (Coord.X, Coord.Y, Coord.Z);
} }
} }
glEnd();
glPopMatrix(); // set up client states for base pass
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// set up texture environment for base pass
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
// render base passes for each patch
for (i=0;i<m_TerrainPatches.size();++i) {
CPatch* patch=m_TerrainPatches[i].m_Object;
CPatchRData* patchdata=(CPatchRData*) patch->m_RenderData;
patchdata->RenderBase();
}
// switch on the composite alpha map texture
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,m_CompositeAlphaMap);
// setup additional texenv required by blend pass
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
// switch on blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// no need to write to the depth buffer a second time
glDepthMask(0);
glClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// render blend passes for each patch
for (i=0;i<m_TerrainPatches.size();++i) {
CPatch* patch=m_TerrainPatches[i].m_Object;
CPatchRData* patchdata=(CPatchRData*) patch->m_RenderData;
patchdata->RenderBlends();
}
glClientActiveTexture(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// restore depth writes
glDepthMask(1);
// restore default state: switch off blending
glDisable(GL_BLEND);
// switch off texture unit 1, make unit 0 active texture
glActiveTexture(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
// switch off all client states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glClientActiveTexture(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
} }
// try and load the given texture // try and load the given texture
bool CRenderer::LoadTexture(CTexture* texture) bool CRenderer::LoadTexture(CTexture* texture)
{ {
Handle h=texture->GetHandle(); Handle h=texture->GetHandle();
if (h) { if (h) {
// already tried to load this texture, nothing to do here - just return accord to whether this // already tried to load this texture, nothing to do here - just return success according
// is a valid handle // to whether this is a valid handle or not
return h==0xfffffff ? true : false; return h==0xfffffff ? true : false;
} else { } else {
h=tex_load(texture->GetName()); h=tex_load(texture->GetName());
@ -250,7 +540,7 @@ bool CRenderer::LoadTexture(CTexture* texture)
} }
// set the given unit to reference the given texture; pass a null texture to disable texturing on any unit // set the given unit to reference the given texture; pass a null texture to disable texturing on any unit
void CRenderer::SetTexture(int unit,CTexture* texture) void CRenderer::SetTexture(int unit,CTexture* texture,u32 wrapflags)
{ {
glActiveTexture(GL_TEXTURE0+unit); glActiveTexture(GL_TEXTURE0+unit);
if (texture) { if (texture) {
@ -258,6 +548,11 @@ void CRenderer::SetTexture(int unit,CTexture* texture)
if (!h) { if (!h) {
LoadTexture(texture); LoadTexture(texture);
h=texture->GetHandle(); h=texture->GetHandle();
if (wrapflags) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapflags);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapflags);
}
} }
// disable texturing if invalid handle // disable texturing if invalid handle
@ -273,247 +568,147 @@ void CRenderer::SetTexture(int unit,CTexture* texture)
} }
} }
void CRenderer::RenderPatchBase (CPatch *patch) bool CRenderer::IsTextureTransparent(CTexture* texture)
{ {
CMiniPatch *MPatch, *MPCurrent; if (texture) {
Handle h=texture->GetHandle();
float StartU, StartV; if (!h) {
LoadTexture(texture);
h=texture->GetHandle();
for (int j=0; j<16; j++) if (h!=0xffffffff) {
{ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
for (int i=0; i<16; i++) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
{
MPatch = &(patch->m_MiniPatches[j][i]);
if (MPatch->m_LastRenderedFrame == m_FrameCounter)
continue;
glActiveTexture (GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
tex_bind(MPatch->Tex1);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
/////////////////////////////////////
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
/////////////////////////////////////
StartU = 0.125f * (float)(i%8);
StartV = 0.125f * (float)(j%8);
float tu[2], tv[2];
tu[0] = tu[1] = StartU;
tv[0] = StartV+0.125f;
tv[1] = StartV;
MPCurrent = MPatch;
glBegin (GL_TRIANGLE_STRIP);
int start = 0;
while (MPCurrent)
{
for (int x=start; x<2; x++)
{
int v1 = MAP_SIZE + x;
int v2 = x;
glTexCoord2f (tu[0], tv[0]);
if (g_HillShading)
glColor3fv(&MPCurrent->m_pVertices[v1].m_Color.X);
else
glColor3f (1,1,1);
glVertex3f (MPCurrent->m_pVertices[v1].m_Position.X,
MPCurrent->m_pVertices[v1].m_Position.Y,
MPCurrent->m_pVertices[v1].m_Position.Z);
glTexCoord2f (tu[1], tv[1]);
if (g_HillShading)
glColor3fv(&MPCurrent->m_pVertices[v2].m_Color.X);
else
glColor3f (1,1,1);
glVertex3f (MPCurrent->m_pVertices[v2].m_Position.X,
MPCurrent->m_pVertices[v2].m_Position.Y,
MPCurrent->m_pVertices[v2].m_Position.Z);
tu[0]+=0.125f;
tu[1]+=0.125f;
}
MPCurrent->m_LastRenderedFrame = m_FrameCounter;
MPCurrent->m_RenderStage = RENDER_STAGE_BASE;
if (!MPCurrent->m_pRightNeighbor)
break;
else
{
if (MPCurrent->m_pRightNeighbor->Tex1 != MPCurrent->Tex1 ||
MPCurrent->m_pRightNeighbor->m_pParrent->m_LastVisFrame != m_FrameCounter)
break;
}
MPCurrent = MPCurrent->m_pRightNeighbor;
start = 1;
} }
}
glEnd (); if (h!=0xffffffff && h) {
int fmt;
int bpp;
tex_info(h, NULL, NULL, &fmt, &bpp, NULL);
if (bpp==24 || fmt == GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
{
return false;
}
return true;
} else {
return false;
} }
} else {
return false;
} }
} }
void CRenderer::RenderPatchTrans (CPatch *patch) static int RoundUpToPowerOf2(int x)
{ {
CMiniPatch *MPatch, *MPCurrent; if ((x & (x-1))==0) return x;
int d=x;
while (d & (d-1)) {
d&=(d-1);
}
return d<<1;
}
float StartU, StartV;
inline void CopyTriple(unsigned char* dst,const unsigned char* src)
{
dst[0]=src[0];
dst[1]=src[1];
dst[2]=src[2];
}
// LoadAlphaMaps: load the 14 default alpha maps, pack them into one composite texture and
// calculate the coordinate of each alphamap within this packed texture .. need to add
// validation that all maps are the same size
bool CRenderer::LoadAlphaMaps(const char* fnames[])
{
glActiveTexture(GL_TEXTURE0_ARB);
glEnable (GL_BLEND); Handle textures[NumAlphaMaps];
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
int i;
for (int j=0; j<16; j++) for (i=0;i<NumAlphaMaps;i++) {
{ textures[i]=tex_load(fnames[i]);
for (int i=0; i<16; i++) if (textures[i] <= 0) {
{ return false;
MPatch = &(patch->m_MiniPatches[j][i]);
if (MPatch->m_LastRenderedFrame == m_FrameCounter &&
MPatch->m_RenderStage == RENDER_STAGE_TRANS)
continue;
//now for transition
if (MPatch->Tex2 && MPatch->m_AlphaMap)
{
glActiveTexture (GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
tex_bind(MPatch->Tex2);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
/////////////////////////////////////
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
/////////////////////////////////////
glActiveTexture (GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
tex_bind(MPatch->m_AlphaMap);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
/////////////////////////////////////
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
/////////////////////////////////////
StartU = 0.125f * (float)(i%8);
StartV = 0.125f * (float)(j%8);
float tu[2], tv[2];
tu[0] = tu[1] = StartU;
tv[0] = StartV+0.125f;
tv[1] = StartV;
glBegin (GL_TRIANGLE_STRIP);
MPCurrent = MPatch;
int start = 0;
while (MPCurrent)
{
for (int x=start; x<2; x++)
{
int v1 = MAP_SIZE + x;
int v2 = x;
glMultiTexCoord2f (GL_TEXTURE0_ARB, tu[0], tv[0]);
glMultiTexCoord2f (GL_TEXTURE1_ARB, tu[0]*2, tv[0]*2);
if (g_HillShading)
glColor3fv(&MPCurrent->m_pVertices[v1].m_Color.X);
else
glColor3f (1,1,1);
glVertex3f (MPCurrent->m_pVertices[v1].m_Position.X,
MPCurrent->m_pVertices[v1].m_Position.Y,
MPCurrent->m_pVertices[v1].m_Position.Z);
glMultiTexCoord2f (GL_TEXTURE0_ARB, tu[1], tv[1]);
glMultiTexCoord2f (GL_TEXTURE1_ARB, tu[1]*2, tv[1]*2);
if (g_HillShading)
glColor3fv(&MPCurrent->m_pVertices[v1].m_Color.X);
else
glColor3f (1,1,1);
glVertex3f (MPCurrent->m_pVertices[v2].m_Position.X,
MPCurrent->m_pVertices[v2].m_Position.Y,
MPCurrent->m_pVertices[v2].m_Position.Z);
tu[0]+=0.125f;
tu[1]+=0.125f;
}
MPCurrent->m_LastRenderedFrame = m_FrameCounter;
MPCurrent->m_RenderStage = RENDER_STAGE_TRANS;
if (!MPCurrent->m_pRightNeighbor)
break;
else
{
if (MPCurrent->m_pRightNeighbor->Tex2 != MPCurrent->Tex2 ||
MPCurrent->m_pRightNeighbor->m_AlphaMap != MPCurrent->m_AlphaMap ||
MPCurrent->m_pRightNeighbor->m_pParrent->m_LastVisFrame != m_FrameCounter)
break;
}
MPCurrent = MPCurrent->m_pRightNeighbor;
start=1;
}
glEnd ();
}
} }
} }
glDisable (GL_BLEND);
glActiveTexture (GL_TEXTURE1); int base;//=textures[0].width;
glDisable(GL_TEXTURE_2D);
glActiveTexture (GL_TEXTURE0); i=tex_info(textures[0], &base, NULL, NULL, NULL, NULL);
int size=(base+4)*NumAlphaMaps;
int texsize=RoundUpToPowerOf2(size);
unsigned char* data=new unsigned char[texsize*base*3];
// for each tile on row
for (i=0;i<NumAlphaMaps;i++) {
//TEX& tex=textures[i];
int bpp;
// get src of copy
const unsigned char* src;
tex_info(textures[i], NULL, NULL, NULL, &bpp, (void **)&src);
int srcstep=bpp/8;
// get destination of copy
unsigned char* dst=data+3*(i*(base+4));
// for each row of image
for (int j=0;j<base;j++) {
// duplicate first pixel
CopyTriple(dst,src);
dst+=3;
CopyTriple(dst,src);
dst+=3;
// copy a row
for (int k=0;k<base;k++) {
CopyTriple(dst,src);
dst+=3;
src+=srcstep;
}
// duplicate last pixel
CopyTriple(dst,(src-bpp/8));
dst+=3;
CopyTriple(dst,(src-bpp/8));
dst+=3;
// advance write pointer for next row
dst+=3*(texsize-(base+4));
}
m_AlphaMapCoords[i].u0=float(i*(base+4)+2)/float(texsize);
m_AlphaMapCoords[i].u1=float((i+1)*(base+4)-2)/float(texsize);
m_AlphaMapCoords[i].v0=0.0f;
m_AlphaMapCoords[i].v1=1.0f;
}
glGenTextures(1,&m_CompositeAlphaMap);
glBindTexture(GL_TEXTURE_2D,m_CompositeAlphaMap);
glTexImage2D(GL_TEXTURE_2D,0,GL_INTENSITY,texsize,base,0,GL_RGB,GL_UNSIGNED_BYTE,data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
delete[] data;
return true;
} }
void CRenderer::BuildTransparentPasses(CVisual* visual)
{
if (!IsTextureTransparent(visual->m_Model->GetTexture())) {
// ok, no transparency on this model .. ignore it here
return;
}
// add this visual to the transparency renderer for later processing
g_TransparencyRenderer.Add(visual);
}

View File

@ -15,20 +15,31 @@
#define RENDERER_H #define RENDERER_H
#include <vector> #include <vector>
#include "res/res.h"
#include "ogl.h" #include "ogl.h"
#include "Camera.h"
#include "Frustum.h" #include "Frustum.h"
#include "PatchRData.h"
#include "ModelRData.h"
#include "SHCoeffs.h"
#include "Terrain.h"
// necessary declarations // necessary declarations
class CCamera; class CCamera;
class CPatch; class CPatch;
class CModel; class CVisual;
class CSprite; class CSprite;
class CParticleSys; class CParticleSys;
class COverlay; class COverlay;
class CMaterial; class CMaterial;
class CLightEnv; class CLightEnv;
class SPatchRData;
class CTexture; class CTexture;
class CTerrain;
// rendering modes
enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// SSubmission: generalised class representating a submission of objects to renderer // SSubmission: generalised class representating a submission of objects to renderer
@ -63,8 +74,36 @@ struct SVertex2D
class CRenderer class CRenderer
{ {
public: public:
// various enumerations // various enumerations and renderer related constants
enum ETerrainMode { WIREFRAME, FILL }; enum { NumAlphaMaps=14 };
// stats class - per frame counts of number of draw calls, poly counts etc
struct Stats {
// set all stats to zero
void Reset() { memset(this,0,sizeof(*this)); }
// add given stats to this stats
Stats& operator+=(const Stats& rhs) {
m_Counter++;
m_DrawCalls+=rhs.m_DrawCalls;
m_TerrainTris+=rhs.m_TerrainTris;
m_ModelTris+=rhs.m_ModelTris;
m_TransparentTris+=rhs.m_TransparentTris;
m_BlendSplats+=rhs.m_BlendSplats;
return *this;
}
// count of the number of stats added together
u32 m_Counter;
// number of draw calls per frame - total DrawElements + Begin/End immediate mode loops
u32 m_DrawCalls;
// number of terrain triangles drawn
u32 m_TerrainTris;
// number of (non-transparent) model triangles drawn
u32 m_ModelTris;
// number of transparent model triangles drawn
u32 m_TransparentTris;
// number of splat passes for alphamapping
u32 m_BlendSplats;
};
public: public:
// constructor, destructor // constructor, destructor
@ -95,12 +134,11 @@ public:
// submission of objects for rendering; the passed matrix indicating the transform must be scoped such that it is valid beyond // submission of objects for rendering; the passed matrix indicating the transform must be scoped such that it is valid beyond
// the call to frame end, as must the object itself // the call to frame end, as must the object itself
void Submit(CPatch* patch); void Submit(CPatch* patch);
void Submit(CModel* model,CMatrix3D* transform); void Submit(CVisual* visual);
void Submit(CSprite* sprite,CMatrix3D* transform); void Submit(CSprite* sprite,CMatrix3D* transform);
void Submit(CParticleSys* psys,CMatrix3D* transform); void Submit(CParticleSys* psys,CMatrix3D* transform);
void Submit(COverlay* overlay); void Submit(COverlay* overlay);
#if 0
// basic primitive rendering operations in 2 and 3D; handy for debugging stuff, but also useful in // basic primitive rendering operations in 2 and 3D; handy for debugging stuff, but also useful in
// editor tools (eg for highlighting specific terrain patches) // editor tools (eg for highlighting specific terrain patches)
// note: // note:
@ -115,30 +153,53 @@ public:
void RenderLineLoop(int len,const SVertex3D* vertices); void RenderLineLoop(int len,const SVertex3D* vertices);
void RenderTri(const SVertex3D* vertices); void RenderTri(const SVertex3D* vertices);
void RenderQuad(const SVertex3D* vertices); void RenderQuad(const SVertex3D* vertices);
#endif
// set the current lighting environment; (note: the passed pointer is just copied to a variable within the renderer, // set the current lighting environment; (note: the passed pointer is just copied to a variable within the renderer,
// so the lightenv passed must be scoped such that it is not destructed until after the renderer is no longer rendering) // so the lightenv passed must be scoped such that it is not destructed until after the renderer is no longer rendering)
void SetLightEnv(CLightEnv* lightenv); void SetLightEnv(CLightEnv* lightenv) {
m_LightEnv=lightenv;
}
// set the mode to render subsequent terrain patches // set the mode to render subsequent terrain patches
void SetTerrainMode(ETerrainMode mode) { m_TerrainMode=mode; } void SetTerrainRenderMode(ERenderMode mode) { m_TerrainRenderMode=mode; }
// get the mode to render subsequent terrain patches // get the mode to render subsequent terrain patches
ETerrainMode GetTerrainMode() const { return m_TerrainMode; } ERenderMode GetTerrainRenderMode() const { return m_TerrainRenderMode; }
// set the mode to render subsequent models
void SetModelRenderMode(ERenderMode mode) { m_ModelRenderMode=mode; }
// get the mode to render subsequent models
ERenderMode GetModelRenderMode() const { return m_ModelRenderMode; }
// try and load the given texture // try and load the given texture
bool LoadTexture(CTexture* texture); bool LoadTexture(CTexture* texture);
// set the given unit to reference the given texture; pass a null texture to disable texturing on any unit // set the given unit to reference the given texture; pass a null texture to disable texturing on any unit
// note - active texture always set to given unit on exit // note - active texture always set to given unit on exit
void SetTexture(int unit,CTexture* texture); void SetTexture(int unit,CTexture* texture,u32 wrapflags=0);
// query transparency of given texture
bool IsTextureTransparent(CTexture* texture);
// load the default set of alphamaps; return false if any alphamap fails to load, true otherwise
bool LoadAlphaMaps(const char* fnames[]);
// return stats accumulated for current frame
const Stats& GetStats() { return m_Stats; }
inline int GetWidth() const { return m_Width; }
inline int GetHeight() const { return m_Height; }
protected: protected:
friend class CPatchRData;
friend class CModelRData;
friend class CTransparencyRenderer;
// patch rendering stuff // patch rendering stuff
void RenderPatchBase(CPatch* patch); void RenderPatchSubmissions();
void RenderPatchTrans(CPatch* patch); void RenderPatches();
// model rendering stuff // model rendering stuff
void RenderModel(SSubmission<CModel*>& modelsub); void BuildTransparentPasses(CVisual* visual);
void RenderModelSubmissions();
void RenderModels();
// RENDERER DATA: // RENDERER DATA:
// view width // view width
@ -150,15 +211,40 @@ protected:
// frame counter // frame counter
int m_FrameCounter; int m_FrameCounter;
// current terrain rendering mode // current terrain rendering mode
ETerrainMode m_TerrainMode; ERenderMode m_TerrainRenderMode;
// current model rendering mode
ERenderMode m_ModelRenderMode;
// current view camera
CCamera m_Camera;
// submitted object lists for batching // submitted object lists for batching
std::vector<SSubmission<CPatch*> > m_TerrainPatches; std::vector<SSubmission<CPatch*> > m_TerrainPatches;
std::vector<SSubmission<CModel*> > m_Models; std::vector<SSubmission<CVisual*> > m_Models;
std::vector<SSubmission<CSprite*> > m_Sprites; std::vector<SSubmission<CSprite*> > m_Sprites;
std::vector<SSubmission<CParticleSys*> > m_ParticleSyses; std::vector<SSubmission<CParticleSys*> > m_ParticleSyses;
std::vector<SSubmission<COverlay*> > m_Overlays; std::vector<SSubmission<COverlay*> > m_Overlays;
// current lighting setup // current lighting setup
CLightEnv* m_LightEnv; CLightEnv* m_LightEnv;
// current spherical harmonic coefficients (for unit lighting), derived from lightenv
CSHCoeffs m_SHCoeffsUnits;
// current spherical harmonic coefficients (for terrain lighting), derived from lightenv
CSHCoeffs m_SHCoeffsTerrain;
// default alpha maps
//Handle m_AlphaMaps[NumAlphaMaps];
// all the alpha maps packed into one texture
unsigned int m_CompositeAlphaMap;
// coordinates of each (untransformed) alpha map within the packed texture
struct {
float u0,u1,v0,v1;
} m_AlphaMapCoords[NumAlphaMaps];
// card capabilities
struct Caps {
bool m_VBO;
} m_Caps;
// build card cap bits
void EnumCaps();
// per-frame renderer stats
Stats m_Stats;
}; };

View File

@ -12,6 +12,11 @@
#include "SHCoeffs.h" #include "SHCoeffs.h"
CSHCoeffs::CSHCoeffs() CSHCoeffs::CSHCoeffs()
{
Clear();
}
void CSHCoeffs::Clear()
{ {
for (int i=0;i<9;i++) { for (int i=0;i<9;i++) {
_data[i].Clear(); _data[i].Clear();
@ -45,7 +50,7 @@ void CSHCoeffs::AddDirectionalLight(const CVector3D& lightDir,const RGBColor& li
_data[8]+=lightColor*c5*(SQR(dirToLight.X)-SQR(dirToLight.Y)); _data[8]+=lightColor*c5*(SQR(dirToLight.X)-SQR(dirToLight.Y));
} }
void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color) void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color) const
{ {
#if 1 #if 1
color=_data[0]; color=_data[0];

View File

@ -19,10 +19,12 @@ class CSHCoeffs
public: public:
CSHCoeffs(); CSHCoeffs();
void Clear();
void AddAmbientLight(const RGBColor& color); void AddAmbientLight(const RGBColor& color);
void AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor); void AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor);
void Evaluate(const CVector3D& normal,RGBColor& color); void Evaluate(const CVector3D& normal,RGBColor& color) const;
const RGBColor* GetCoefficients() const { return _data; } const RGBColor* GetCoefficients() const { return _data; }

View File

@ -12,18 +12,9 @@
#ifndef TERRGLOBALS_H #ifndef TERRGLOBALS_H
#define TERRGLOBALS_H #define TERRGLOBALS_H
const int PATCH_SIZE = 16; const int PATCH_SIZE = 16;
const int CELL_SIZE = 4; //horizontal scale of the patches const int CELL_SIZE = 4; //horizontal scale of the patches
const float HEIGHT_SCALE = 0.35f; const float HEIGHT_SCALE = 0.35f/256.0f;
//only 3x3 patches loaded at a time
const int NUM_PATCHES_PER_SIDE = 20;
//must be odd number of patches
//#define TERRAIN_CHUNK_SIZE (PATCH_SIZE*NUM_PATCHES_PER_SIDE)
const int MAP_SIZE = ( (NUM_PATCHES_PER_SIDE*PATCH_SIZE)+1 );
#endif #endif

View File

@ -14,182 +14,267 @@
// //
//*********************************************************** //***********************************************************
#include "res/res.h"
#include "res/tex.h"
#include "res/mem.h"
#include <string.h>
#include "Terrain.h" #include "Terrain.h"
#include "LightEnv.h"
#include "SHCoeffs.h"
bool g_HillShading = true;
CVector3D SeasonLight[2]; CTerrain::CTerrain()
float SeasonColor[2][3];
CTerrain::CTerrain ()
{ {
m_pVertices = NULL; m_Heightmap = NULL;
m_Patches = NULL;
m_MapSize = 0;
m_MapSizePatches = 0;
} }
CTerrain::~CTerrain () CTerrain::~CTerrain()
{ {
delete [] m_pVertices; Reset();
} }
bool CTerrain::Load(char *filename)
{
Handle ht = tex_load(filename);
if(!ht)
return false;
void* p;
tex_info(ht, 0, 0, &p);
return InitFromHeightmap((const u8*)p); void CTerrain::Reset()
{
delete[] m_Heightmap;
delete[] m_Patches;
} }
bool CTerrain::InitFromHeightmap(const u8* data)
bool CTerrain::Initialize(u32 size,const u16* data)
{ {
int j; // clean up any previous terrain
Reset();
delete[] m_pVertices; // store terrain size
m_MapSize=(size*PATCH_SIZE)+1;
m_MapSizePatches=size;
m_pVertices = new STerrainVertex[MAP_SIZE*MAP_SIZE]; // allocate data for new terrain
if (m_pVertices == NULL) m_Heightmap=new u16[m_MapSize*m_MapSize];
return false; m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches];
for (j=0; j<MAP_SIZE; j++) // given a heightmap?
{ if (data) {
for (int i=0; i<MAP_SIZE; i++) // yes; keep a copy of it
{ memcpy(m_Heightmap,data,m_MapSize*m_MapSize*sizeof(u16));
int pos = j*MAP_SIZE + i; } else {
// build a flat terrain
m_pVertices[pos].m_Position.X = ((float)i)*CELL_SIZE; memset(m_Heightmap,0,m_MapSize*m_MapSize*sizeof(u16));
m_pVertices[pos].m_Position.Y = (*data++)*HEIGHT_SCALE;
m_pVertices[pos].m_Position.Z = ((float)j)*CELL_SIZE;
}
} }
for (j=0; j<NUM_PATCHES_PER_SIDE; j++) // setup patch parents, indices etc
{ InitialisePatches();
for (int i=0; i<NUM_PATCHES_PER_SIDE; i++)
{
int pos = j*MAP_SIZE*PATCH_SIZE;
pos += i*PATCH_SIZE;
m_Patches[j][i].Initialize ( &(m_pVertices[pos]) );
}
}
CalcNormals();
SetNeighbors();
return true; return true;
} }
void CTerrain::CalcLighting(const CLightEnv& lightEnv) void CTerrain::CalcPosition(u32 i,u32 j,CVector3D& pos)
{ {
CSHCoeffs coeffs; u16 height=m_Heightmap[j*m_MapSize + i];
coeffs.AddAmbientLight(lightEnv.m_TerrainAmbientColor); pos.X = float(i)*CELL_SIZE;
pos.Y = float(height)*HEIGHT_SCALE;
CVector3D dirlight; pos.Z = float(j)*CELL_SIZE;
lightEnv.GetSunDirection(dirlight);
coeffs.AddDirectionalLight(dirlight,lightEnv.m_SunColor);
for (int k=0;k<MAP_SIZE*MAP_SIZE;++k) {
coeffs.Evaluate(m_pVertices[k].m_Normal,m_pVertices[k].m_Color);
}
} }
void CTerrain::CalcNormals()
{ void CTerrain::CalcNormal(u32 i,u32 j,CVector3D& normal)
CVector3D left, right, up, down, n[4]; {
CVector3D left, right, up, down;
for (int j=0; j<MAP_SIZE; j++) left.Clear();
{ right.Clear();
for (int i=0; i<MAP_SIZE; i++) up.Clear();
{ down.Clear();
left.Clear();
right.Clear(); // get position of vertex where normal is being evaluated
up.Clear(); CVector3D basepos;
down.Clear(); CalcPosition(i,j,basepos);
if (i>0)
left = m_pVertices[j*MAP_SIZE + i - 1].m_Position -
m_pVertices[j*MAP_SIZE + i].m_Position;
if (i<MAP_SIZE-1) CVector3D tmp;
right = m_pVertices[j*MAP_SIZE + i + 1].m_Position - if (i>0) {
m_pVertices[j*MAP_SIZE + i].m_Position; CalcPosition(i-1,j,tmp);
left=tmp-basepos;
}
if (j>0) if (i<m_MapSize-1) {
up = m_pVertices[(j-1)*MAP_SIZE + i].m_Position - CalcPosition(i+1,j,tmp);
m_pVertices[j*MAP_SIZE + i].m_Position; right=tmp-basepos;
}
if (j<MAP_SIZE-1) if (j>0) {
down = m_pVertices[(j+1)*MAP_SIZE + i].m_Position - CalcPosition(i,j-1,tmp);
m_pVertices[j*MAP_SIZE + i].m_Position; up=tmp-basepos;
}
n[0] = up.Cross(left); if (j<m_MapSize-1) {
n[1] = left.Cross(down); CalcPosition(i,j+1,tmp);
n[2] = down.Cross(right); down=tmp-basepos;
n[3] = right.Cross(up); }
float n0len=n[0].GetLength(); CVector3D n0 = up.Cross(left);
if (n0len>0.0001f) n[0]*=1.0f/n0len; CVector3D n1 = left.Cross(down);
CVector3D n2 = down.Cross(right);
CVector3D n3 = right.Cross(up);
float n1len=n[1].GetLength(); normal = n0 + n1 + n2 + n3;
if (n1len>0.0001f) n[1]*=1.0f/n1len; float nlen=normal.GetLength();
if (nlen>0.00001f) normal*=1.0f/nlen;
}
float n2len=n[2].GetLength();
if (n2len>0.0001f) n[2]*=1.0f/n2len;
float n3len=n[3].GetLength(); CPatch* CTerrain::GetPatch(int32 x,int32 z)
if (n3len>0.0001f) n[3]*=1.0f/n3len; {
if (x<0 || x>=int32(m_MapSizePatches)) return 0;
if (z<0 || z>=int32(m_MapSizePatches)) return 0;
return &m_Patches[(z*m_MapSizePatches)+x];
}
CVector3D Normal = n[0] + n[1] + n[2] + n[3]; CMiniPatch* CTerrain::GetTile(int32 x,int32 z)
float nlen=Normal.GetLength(); {
if (nlen>0.00001f) Normal*=1.0f/nlen; if (x<0 || x>=int32(m_MapSize)-1) return 0;
if (z<0 || z>=int32(m_MapSize)-1) return 0;
m_pVertices[j*MAP_SIZE + i].m_Normal=Normal;
CPatch* patch=GetPatch(x/16,z/16);
return &patch->m_MiniPatches[z%16][x%16];
}
void CTerrain::Resize(u32 size)
{
if (size==m_MapSizePatches) {
// inexplicable request to resize terrain to the same size .. ignore it
return;
}
if (!m_Heightmap) {
// not yet created a terrain; build a default terrain of the given size now
Initialize(size,0);
return;
}
// allocate data for new terrain
u32 newMapSize=(size*PATCH_SIZE)+1;
u16* newHeightmap=new u16[newMapSize*newMapSize];
CPatch* newPatches=new CPatch[size*size];
if (size>m_MapSizePatches) {
// new map is bigger than old one - zero the heightmap so we don't get uninitialised
// height data along the expanded edges
memset(newHeightmap,0,newMapSize*newMapSize);
}
// now copy over rows of data
u32 j;
u16* src=m_Heightmap;
u16* dst=newHeightmap;
u32 copysize=newMapSize>m_MapSize ? m_MapSize : newMapSize;
for (j=0;j<copysize;j++) {
memcpy(dst,src,copysize*sizeof(u16));
dst+=copysize;
src+=m_MapSize;
if (newMapSize>m_MapSize) {
// entend the last height to the end of the row
for (u32 i=0;i<newMapSize-m_MapSize;i++) {
*dst++=*(src-1);
}
}
}
if (newMapSize>m_MapSize) {
// copy over heights of the last row to any remaining rows
src=newHeightmap+((m_MapSize-1)*newMapSize);
dst=src+newMapSize;
for (u32 i=0;i<newMapSize-m_MapSize;i++) {
memcpy(dst,src,newMapSize*sizeof(u16));
dst+=newMapSize;
} }
} }
}
void CTerrain::SetNeighbors () // now build new patches
{ for (j=0;j<size;j++) {
CPatch *ThisPatch, *RightPatch; for (u32 i=0;i<size;i++) {
// copy over texture data from existing tiles, if possible
if (i<m_MapSizePatches && j<m_MapSizePatches) {
memcpy(newPatches[j*size+i].m_MiniPatches,m_Patches[j*m_MapSizePatches+i].m_MiniPatches,sizeof(CMiniPatch)*16*16);
}
}
for (int pj=0; pj<NUM_PATCHES_PER_SIDE; pj++) if (j<m_MapSizePatches && size>m_MapSizePatches) {
{ // copy over the last tile from each column
for (int pi=0; pi<NUM_PATCHES_PER_SIDE; pi++) for (u32 n=0;n<size-m_MapSizePatches;n++) {
{ for (int m=0;m<16;m++) {
ThisPatch = &m_Patches[pj][pi]; CMiniPatch& src=m_Patches[j*m_MapSizePatches+m_MapSizePatches-1].m_MiniPatches[m][15];
for (int k=0;k<16;k++) {
if (pi < NUM_PATCHES_PER_SIDE-1) CMiniPatch& dst=newPatches[j*size+m_MapSizePatches+n].m_MiniPatches[m][k];
RightPatch = &m_Patches[pj][pi+1]; dst.Tex1=src.Tex1;
else dst.Tex1Priority=src.Tex1Priority;
RightPatch = NULL;
for (int tj=0; tj<16; tj++)
{
for (int ti=0; ti<16; ti++)
{
CMiniPatch *MPatch = &ThisPatch->m_MiniPatches[tj][ti];
MPatch->m_pParrent = ThisPatch;
if (ti < 15)
MPatch->m_pRightNeighbor = &ThisPatch->m_MiniPatches[tj][ti+1];
else
{
if (RightPatch)
MPatch->m_pRightNeighbor = &RightPatch->m_MiniPatches[tj][0];
else
MPatch->m_pRightNeighbor = NULL;
} }
} }
} }
} }
} }
if (size>m_MapSizePatches) {
// copy over the last tile from each column
CPatch* srcpatch=&newPatches[(m_MapSizePatches-1)*size];
CPatch* dstpatch=srcpatch+size;
for (u32 p=0;p<size-m_MapSizePatches;p++) {
for (u32 n=0;n<size;n++) {
for (int m=0;m<16;m++) {
for (int k=0;k<16;k++) {
CMiniPatch& src=srcpatch->m_MiniPatches[15][k];
CMiniPatch& dst=dstpatch->m_MiniPatches[m][k];
dst.Tex1=src.Tex1;
dst.Tex1Priority=src.Tex1Priority;
}
}
srcpatch++;
dstpatch++;
}
}
}
// release all the original data
Reset();
// store new data
m_Heightmap=newHeightmap;
m_Patches=newPatches;
m_MapSize=newMapSize;
m_MapSizePatches=size;
// initialise all the new patches
InitialisePatches();
}
void CTerrain::InitialisePatches()
{
for (u32 j=0;j<m_MapSizePatches;j++) {
for (u32 i=0;i<m_MapSizePatches;i++) {
CPatch* patch=GetPatch(i,j);
patch->Initialize(this,i,j);
}
}
}
// SetHeightMap: set up a new heightmap from 16-bit source data;
// assumes heightmap matches current terrain size
void CTerrain::SetHeightMap(u16* heightmap)
{
// keep a copy of the given heightmap
memcpy(m_Heightmap,heightmap,m_MapSize*m_MapSize*sizeof(u16));
// recalculate patch bounds, invalidate vertices
for (u32 j=0;j<m_MapSizePatches;j++) {
for (u32 i=0;i<m_MapSizePatches;i++) {
CPatch* patch=GetPatch(i,j);
patch->CalcBounds();
if (patch->m_RenderData) patch->m_RenderData->m_UpdateFlags|=RENDERDATA_UPDATE_VERTICES;
}
}
} }

View File

@ -17,34 +17,62 @@
#ifndef TERRAIN_H #ifndef TERRAIN_H
#define TERRAIN_H #define TERRAIN_H
#include <stdio.h>
#include "Patch.h" #include "Patch.h"
#include "Vector3D.h" #include "Vector3D.h"
#include "TerrGlobals.h"
class CLightEnv; class CLightEnv;
class CSHCoeffs;
extern bool g_HillShading;
class CTerrain class CTerrain
{ {
public: public:
CTerrain (); CTerrain();
~CTerrain (); ~CTerrain();
bool Load(char *filename); bool Initialize(u32 size,const u16* ptr);
bool InitFromHeightmap(const u8* data);
// protected: // return number of vertices along edge of the terrain
//the patches currently loaded u32 GetVerticesPerSide() { return m_MapSize; }
CPatch m_Patches[NUM_PATCHES_PER_SIDE][NUM_PATCHES_PER_SIDE]; // return number of patches along edge of the terrain
STerrainVertex *m_pVertices; u32 GetPatchesPerSide() { return m_MapSizePatches; }
// resize this terrain such that each side has given number of patches
void Resize(u32 size);
// set up a new heightmap from 16 bit data; assumes heightmap matches current terrain size
void SetHeightMap(u16* heightmap);
// return a pointer to the heightmap
u16* GetHeightMap() const { return m_Heightmap; }
// get patch at given coordinates, expressed in patch-space; return 0 if
// coordinates represent patch off the edge of the map
CPatch* GetPatch(int32 x,int32 z);
// get tile at given coordinates, expressed in tile-space; return 0 if
// coordinates represent tile off the edge of the map
CMiniPatch* GetTile(int32 x,int32 z);
// calculate the position of a given vertex
void CalcPosition(u32 i,u32 j,CVector3D& pos);
// calculate the normal at a given vertex
void CalcNormal(u32 i,u32 j,CVector3D& normal);
private:
// clean up terrain data
void Reset();
// setup patch pointers etc
void InitialisePatches();
// size of this map in each direction, in vertices; ie. total tiles = sqr(m_MapSize-1)
u32 m_MapSize;
// size of this map in each direction, in patches; total patches = sqr(m_MapSizePatches)
u32 m_MapSizePatches;
// the patches comprising this terrain
CPatch* m_Patches;
// 16-bit heightmap data
u16* m_Heightmap;
// protected:
void CalcNormals();
void CalcLighting(const CLightEnv& env);
void SetNeighbors();
}; };
#endif #endif

View File

@ -80,7 +80,7 @@ CTextureEntry* CTextureManager::AddTexture(const char* filename,int type)
{ {
assert(type<m_TerrainTextures.size()); assert(type<m_TerrainTextures.size());
CStr pathname("terrains/textures/"); CStr pathname("art/textures/terrain/types/");
pathname+=m_TerrainTextures[type].m_Name; pathname+=m_TerrainTextures[type].m_Name;
pathname+='/'; pathname+='/';
pathname+=filename; pathname+=filename;
@ -151,7 +151,7 @@ void CTextureManager::LoadTerrainTextures(int terraintype,const char* fileext)
long handle; long handle;
// build pathname // build pathname
CStr pathname("terrains\\textures\\"); CStr pathname("mods\\official\\art\\textures\\terrain\\types\\");
pathname+=m_TerrainTextures[terraintype].m_Name; pathname+=m_TerrainTextures[terraintype].m_Name;
pathname+="\\"; pathname+="\\";
@ -181,7 +181,7 @@ void CTextureManager::BuildTerrainTypes()
long handle; long handle;
// Find first matching directory in terrain\textures // Find first matching directory in terrain\textures
if ((handle=_findfirst("terrains\\textures\\*",&file))!=-1) { if ((handle=_findfirst("mods\\official\\art\\textures\\terrain\\types\\*",&file))!=-1) {
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.' && file.name[0]!='_') { if ((file.attrib & _A_SUBDIR) && file.name[0]!='.' && file.name[0]!='_') {
AddTextureType(file.name); AddTextureType(file.name);

View File

@ -59,4 +59,4 @@ class CVector3D;
class CWorld; class CWorld;
#endif #endif

View File

@ -1,14 +1,16 @@
#include "Matrix3D.h" #include "Matrix3D.h"
#include "Renderer.h" #include "Renderer.h"
#include "Terrain.h" #include "Terrain.h"
#include "Camera.h"
#include "LightEnv.h" #include "LightEnv.h"
#include "TextureManager.h"
#include "Prometheus.h" #include "Prometheus.h"
#include "detect.h"
#include "time.h" #include "time.h"
#include "sdl.h" #include "sdl.h"
#include "res/res.h" #include "res/tex.h"
#include "detect.h"
#include <malloc.h>
// TODO: fix scrolling hack - framerate independent, use SDL // TODO: fix scrolling hack - framerate independent, use SDL
//#include "win.h" // REMOVEME //#include "win.h" // REMOVEME
@ -37,15 +39,8 @@ double g_LastTime;
const int NUM_ALPHA_MAPS = 13; const int NUM_ALPHA_MAPS = 13;
//CTexture g_BaseTexture[5];
Handle BaseTexs[5];
Handle AlphaMaps[NUM_ALPHA_MAPS];
//CTexture g_TransitionTexture[NUM_ALPHA_MAPS];
int mouse_x=50, mouse_y=50; int mouse_x=50, mouse_y=50;
void terr_init() void terr_init()
{ {
int xres,yres; int xres,yres;
@ -69,10 +64,10 @@ void terr_update()
g_Renderer.BeginFrame(); g_Renderer.BeginFrame();
g_Renderer.SetCamera(g_Camera); g_Renderer.SetCamera(g_Camera);
///////////////////////////////////////////// // switch on wireframe for terrain if we want it
/*POINT MousePos; g_Renderer.SetTerrainRenderMode(SOLID);
GetCursorPos (&MousePos);*/ /////////////////////////////////////////////
CVector3D right(1,0,1); CVector3D right(1,0,1);
CVector3D up(1,0,-1); CVector3D up(1,0,-1);
right.Normalize (); right.Normalize ();
@ -106,22 +101,21 @@ void terr_update()
CFrustum frustum=g_Camera.GetFustum(); CFrustum frustum=g_Camera.GetFustum();
// iterate through patches; cull everything not visible // iterate through patches; cull everything not visible
for (int j=0; j<NUM_PATCHES_PER_SIDE; j++) for (uint j=0; j<g_Terrain.GetPatchesPerSide(); j++)
{ {
for (int i=0; i<NUM_PATCHES_PER_SIDE; i++) for (uint i=0; i<g_Terrain.GetPatchesPerSide(); i++)
{ {
if (frustum.IsBoxVisible (CVector3D(0,0,0),g_Terrain.m_Patches[j][i].m_Bounds)) { if (frustum.IsBoxVisible (CVector3D(0,0,0),g_Terrain.GetPatch(j, i)->GetBounds())) {
g_Renderer.Submit(&g_Terrain.m_Patches[j][i]); g_Renderer.Submit(g_Terrain.GetPatch(j, i));
} }
} }
} }
// flush the frame to force terrain to be renderered before overlays // flush the frame to force terrain to be renderered before overlays
g_Renderer.FlushFrame(); g_Renderer.FlushFrame();
// g_Renderer.RenderTileOutline (&(g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX])); // g_Renderer.RenderTileOutline (&(g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]));
// mark end of frame
g_Renderer.EndFrame(); g_Renderer.EndFrame();
} }
@ -142,11 +136,11 @@ bool terr_handler(const SDL_Event& ev)
case SDL_KEYDOWN: case SDL_KEYDOWN:
switch(ev.key.keysym.sym) switch(ev.key.keysym.sym)
{ {
case 'W': case 'W':
if (g_Renderer.GetTerrainMode()==CRenderer::WIREFRAME) { if (g_Renderer.GetTerrainRenderMode()==WIREFRAME) {
g_Renderer.SetTerrainMode(CRenderer::FILL); g_Renderer.SetTerrainRenderMode(SOLID);
} else { } else {
g_Renderer.SetTerrainMode(CRenderer::WIREFRAME); g_Renderer.SetTerrainRenderMode(WIREFRAME);
} }
break; break;
@ -158,14 +152,14 @@ bool terr_handler(const SDL_Event& ev)
g_Camera.m_Orientation.Translate (100, 150, -100); g_Camera.m_Orientation.Translate (100, 150, -100);
break; break;
case 'L': /* case 'L':
g_HillShading = !g_HillShading; g_HillShading = !g_HillShading;
break; break;*/
// tile selection // tile selection
case SDLK_DOWN: case SDLK_DOWN:
if(++SelTX > 15) if(++SelTX > 15)
if(SelPX == NUM_PATCHES_PER_SIDE-1) if(SelPX == g_Terrain.GetPatchesPerSide()-1)
SelTX = 15; SelTX = 15;
else else
SelTX = 0, SelPX++; SelTX = 0, SelPX++;
@ -180,7 +174,7 @@ bool terr_handler(const SDL_Event& ev)
break; break;
case SDLK_RIGHT: case SDLK_RIGHT:
if(++SelTY > 15) if(++SelTY > 15)
if(SelPY == NUM_PATCHES_PER_SIDE-1) if(SelPY == g_Terrain.GetPatchesPerSide()-1)
SelTY = 15; SelTY = 15;
else else
SelTY = 0, SelPY++; SelTY = 0, SelPY++;
@ -197,8 +191,8 @@ bool terr_handler(const SDL_Event& ev)
case SDLK_KP0: case SDLK_KP0:
{ {
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]; CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX];
if (!MPatch->Tex2) /*if (!MPatch->Tex2)
{ {
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter]; MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
MPatch->Tex2 = BaseTexs[g_SecTexCounter]; MPatch->Tex2 = BaseTexs[g_SecTexCounter];
@ -207,13 +201,13 @@ bool terr_handler(const SDL_Event& ev)
{ {
MPatch->Tex2 = 0; MPatch->Tex2 = 0;
MPatch->m_AlphaMap = 0; MPatch->m_AlphaMap = 0;
} }*/
break; break;
} }
case SDLK_KP1: /*case SDLK_KP1:
{ {
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]; CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX];
g_BaseTexCounter++; g_BaseTexCounter++;
if (g_BaseTexCounter > 4) if (g_BaseTexCounter > 4)
@ -243,7 +237,7 @@ bool terr_handler(const SDL_Event& ev)
{ {
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]; CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
if (MPatch->/*m_pTransitionTexture*/m_AlphaMap) if (MPatch->m_AlphaMap)
{ {
g_TransTexCounter++; g_TransTexCounter++;
if (g_TransTexCounter >= NUM_ALPHA_MAPS) if (g_TransTexCounter >= NUM_ALPHA_MAPS)
@ -253,7 +247,7 @@ bool terr_handler(const SDL_Event& ev)
} }
break; break;
} }*/
} }
} }
@ -267,32 +261,61 @@ bool terr_handler(const SDL_Event& ev)
void InitScene () void InitScene ()
{ {
// setup default lighting environment // setup default lighting environment
g_LightEnv.m_SunColor=RGBColor(0.75f,0.70f,0.65f); g_LightEnv.m_SunColor=RGBColor(1,1,1);
g_LightEnv.m_Rotation=270; g_LightEnv.m_Rotation=DEGTORAD(270);
g_LightEnv.m_Elevation=DEGTORAD(30); g_LightEnv.m_Elevation=DEGTORAD(45);
g_LightEnv.m_TerrainAmbientColor=RGBColor(0.0f,0.0f,0.0f); g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0);
g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f);
g_Renderer.SetLightEnv(&g_LightEnv);
g_Terrain.Load("terrain.raw"); // load terrain
Handle ht = tex_load("terrain.raw");
for (int pj=0; pj<NUM_PATCHES_PER_SIDE; pj++) if(ht > 0)
{ {
for (int pi=0; pi<NUM_PATCHES_PER_SIDE; pi++) const u8* p;
{ int w;
for (int tj=0; tj<16; tj++) int h;
{
for (int ti=0; ti<16; ti++) tex_info(ht, &w, &h, NULL, NULL, (void **)&p);
{
g_Terrain.m_Patches[pj][pi].m_MiniPatches[tj][ti].Tex1 = BaseTexs[0];//rand()%5]; printf("terrain.raw: %dx%d\n", w, h);
g_Terrain.m_Patches[pj][pi].m_MiniPatches[tj][ti].Tex2 = NULL;//&g_BaseTexture[rand()%5];
g_Terrain.m_Patches[pj][pi].m_MiniPatches[tj][ti].m_AlphaMap = 0;//&g_TransitionTexture[rand()%5]; u16 *p16=new u16[w*h];
u16 *p16p=p16;
while (p16p < p16+(w*h))
*p16p++ = (*p++) << 8;
g_Terrain.Resize(20);
g_Terrain.SetHeightMap(p16);
delete[] p16;
tex_free(ht);
}
// get default texture to apply to terrain
CTextureEntry* texture=0;
if (g_TexMan.m_TerrainTextures.size()>0) {
if (g_TexMan.m_TerrainTextures[0].m_Textures.size()) {
texture=g_TexMan.m_TerrainTextures[0].m_Textures[0];
}
}
// cover entire terrain with default texture
u32 patchesPerSide=g_Terrain.GetPatchesPerSide();
for (uint pj=0; pj<patchesPerSide; pj++) {
for (uint pi=0; pi<patchesPerSide; pi++) {
CPatch* patch=g_Terrain.GetPatch(pi,pj);
for (int j=0;j<16;j++) {
for (int i=0;i<16;i++) {
patch->m_MiniPatches[j][i].Tex1=texture ? texture->m_Handle :0;
} }
} }
} }
} }
// calculate terrain lighting
g_Terrain.CalcLighting(g_LightEnv);
g_Camera.SetProjection (1, 1000, DEGTORAD(20)); g_Camera.SetProjection (1, 1000, DEGTORAD(20));
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30)); g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
g_Camera.m_Orientation.RotateY(DEGTORAD(-45)); g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
@ -304,75 +327,29 @@ void InitScene ()
void InitResources() void InitResources()
{ {
int i; #ifndef _WIN32
char* base_fns[] = g_TexMan.AddTextureType("grass");
{ g_TexMan.AddTexture("Base1.tga", 0);
"Base1.bmp",
"Base2.bmp",
"Base3.bmp",
"Base4.bmp",
"Base5.bmp"
};
for(i = 0; i < 5; i++)
{
BaseTexs[i] = tex_load(base_fns[i]);
tex_upload(BaseTexs[i], GL_LINEAR_MIPMAP_LINEAR);
}
int cnt;
#if 1
char* fns[NUM_ALPHA_MAPS] = {
"blendcircle.raw",
"blendcorner.raw",
"blendedge.raw",
"blendedgecorner.raw",
"blendedgetwocorners.raw",
"blendfourcorners.raw",
"blendlshape.raw",
"blendlshapecorner.raw",
"blendthreecorners.raw",
"blendtwocorners.raw",
"blendtwoedges.raw",
"blendtwooppositecorners.raw",
"blendushape.raw"
};
/*
//for(i = 0; i < NUM_ALPHA_MAPS;i++)
i=5;
{
FILE* f = fopen(fns[i],"rb");
u8 buf[5000],buf2[5000];
fread(buf,5000,1,f);
fclose(f);
for(int j = 0; j < 1024; j++)
buf2[2*j] = buf2[2*j+1] = buf[j];
f=fopen(fns[i],"wb");
fwrite(buf2,2048,1,f);
fclose(f);
}
/**/
cnt=13;
#else #else
g_TexMan.LoadTerrainTextures();
char* fns[NUM_ALPHA_MAPS] = {
"Transition1.bmp",
"Transition2.bmp",
"Transition3.bmp",
"Transition4.bmp",
"Transition5.bmp",
};
cnt=5;
#endif #endif
for(i = 0; i < cnt; i++) const char* fns[CRenderer::NumAlphaMaps] = {
{ "art/textures/terrain/alphamaps/special/blendcircle.png",
AlphaMaps[i] = tex_load(fns[i]); "art/textures/terrain/alphamaps/special/blendlshape.png",
tex_upload(AlphaMaps[i], GL_LINEAR, GL_INTENSITY4); "art/textures/terrain/alphamaps/special/blendedge.png",
} "art/textures/terrain/alphamaps/special/blendedgecorner.png",
"art/textures/terrain/alphamaps/special/blendedgetwocorners.png",
"art/textures/terrain/alphamaps/special/blendfourcorners.png",
"art/textures/terrain/alphamaps/special/blendtwooppositecorners.png",
"art/textures/terrain/alphamaps/special/blendlshapecorner.png",
"art/textures/terrain/alphamaps/special/blendtwocorners.png",
"art/textures/terrain/alphamaps/special/blendcorner.png",
"art/textures/terrain/alphamaps/special/blendtwoedges.png",
"art/textures/terrain/alphamaps/special/blendthreecorners.png",
"art/textures/terrain/alphamaps/special/blendushape.png",
"art/textures/terrain/alphamaps/special/blendbad.png"
};
assert(g_Renderer.LoadAlphaMaps(fns));
} }