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
#include <assert.h>
#include <float.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
#include "Vector3D.h"
#include "Matrix3D.h"
class CBound
{
@ -22,6 +23,8 @@ public:
CBound(const CVector3D& min,const CVector3D& 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]; }
const CVector3D& operator[](int index) const { return m_Data[index]; }

View File

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

View File

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

View File

@ -12,12 +12,13 @@
#ifndef MATHUTIL_H
#define MATHUTIL_H
#ifndef PI
#define PI 3.14159265358979323846f
#endif
#define DEGTORAD(a) ((a) * (PI/180.0f))
#define RADTODEG(a) ((a) * (180.0f/PI))
#define SQR(x) ((x) * (x))
#define MAX3(a,b,c) ( MAX (MAX(a,b), c) )
#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
//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;
Temp._21 = _12;
Temp._31 = _13;
Temp._41 = 0.0f;
result._12 = _21;
result._22 = _22;
result._32 = _23;
result._42 = _24;
Temp._12 = _21;
Temp._22 = _22;
Temp._32 = _23;
Temp._42 = 0.0f;
result._13 = _31;
result._23 = _32;
result._33 = _33;
result._43 = _34;
Temp._13 = _31;
Temp._23 = _32;
Temp._33 = _33;
Temp._43 = 0.0f;
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;
result._14 = _41;
result._24 = _42;
result._34 = _43;
result._44 = _44;
}
//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
//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
CVector3D GetLeft () const;

View File

@ -1,22 +1,21 @@
#include "MiniPatch.h"
#include "Patch.h"
CMiniPatch::CMiniPatch()
{
Tex1 = Tex2 = 0;
m_AlphaMap = 0;
m_pRightNeighbor = NULL;
m_pParrent = NULL;
m_Rotation = 0;
m_RenderStage = 0;
m_LastRenderedFrame = 0;
Tex1 = 0;
Tex1Priority = 0;
m_Parent = NULL;
}
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
#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
{
public:
CMiniPatch();
~CMiniPatch();
public:
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;
Handle m_AlphaMap;
CMiniPatch *m_pRightNeighbor;
CPatch *m_pParrent;
unsigned char m_RenderStage;
unsigned int m_LastRenderedFrame;
unsigned char m_Rotation;
STerrainVertex *m_pVertices;
CPatch *m_Parent;
// STerrainVertex *m_pVertices;
};
#endif
#endif

View File

@ -11,11 +11,13 @@
#include "Model.h"
#include "Quaternion.h"
#include "Bound.h"
CModel::CModel()
{
m_pModelDef = NULL;
m_pBonePoses = NULL;
m_RenderData = 0;
}
CModel::~CModel()
@ -126,3 +128,19 @@ void RotateX (CMatrix3D *mat, float angle1, float angle2, float factor)
*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 "ModelDef.h"
#include "RenderableObject.h"
class CModel
class CBound;
class CModel
{
public:
CModel();
@ -27,6 +31,10 @@ class CModel
void SetPose (const char *anim_name, float time);
void ClearPose ();
void CalcBounds(CBound& bound);
CRenderData* m_RenderData;
//access functions
public:
CModelDef *GetModelDef() { return m_pModelDef; }

View File

@ -94,16 +94,19 @@ void CModelDef::SetupBones()
for (i=0; i<m_NumVertices; 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.Y -= BonePos.Y;
pVertex->m_Coords.Z -= BonePos.Z;
pVertex->m_Coords.X -= BonePos.X;
pVertex->m_Coords.Y -= BonePos.Y;
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 GetNumAnimations() { return m_NumAnimations; }
protected:
public:
SModelVertex *m_pVertices;
SModelFace *m_pFaces;
SModelBone *m_pBones;

View File

@ -11,40 +11,51 @@
//***********************************************************
#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 (STerrainVertex *first_vertex)
void CPatch::Initialize(CTerrain* parent,u32 x,u32 z)
{
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();
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++)
{
m_Bounds+=m_pVertices[j*MAP_SIZE + i].m_Position;
}
}
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] );
CVector3D pos;
m_Parent->CalcPosition(m_X*PATCH_SIZE+i,m_Z*PATCH_SIZE+j,pos);
m_Bounds+=pos;
}
}
}

View File

@ -12,27 +12,32 @@
#ifndef PATCH_H
#define PATCH_H
#include "Bound.h"
#include "Matrix3D.h"
#include "Camera.h"
#include "TerrGlobals.h"
#include "MiniPatch.h"
#include "RenderableObject.h"
class CPatch
class CPatch : public CRenderableObject
{
public:
CPatch ();
~CPatch ();
public:
CPatch();
~CPatch();
//initialize the patch
void Initialize (STerrainVertex *first_vertex);
//initialize the patch
void Initialize(CTerrain* parent,u32 x,u32 z);
// protected:
CMiniPatch m_MiniPatches[16][16];
// calculate and store bounds of this patch
void CalcBounds();
CBound m_Bounds;
unsigned int m_LastVisFrame;
STerrainVertex *m_pVertices;
// minipatches (tiles) making up the patch
CMiniPatch m_MiniPatches[16][16];
// position of patch in parent terrain grid
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) {
u32 count=neighbourTextures.size();
size_t count=neighbourTextures.size();
// sort textures from lowest to highest priority
std::sort(neighbourTextures.begin(),neighbourTextures.end());
@ -175,7 +175,7 @@ void CPatchRData::BuildBlends()
int vsize=PATCH_SIZE+1;
SBlendVertex dst;
int vindex=m_BlendVertices.size();
size_t vindex=m_BlendVertices.size();
const SBaseVertex& vtx0=m_Vertices[(j*vsize)+i];
dst.m_UVs[0]=i*0.125f;

View File

@ -10,21 +10,90 @@
// types - terrain, models, sprites, particles etc
//----------------------------------------------------------------
#include <map>
#include <set>
#include <algorithm>
#include "Renderer.h"
#include "TransparencyRenderer.h"
#include "Terrain.h"
#include "Matrix3D.h"
#include "Camera.h"
#include "PatchRData.h"
#include "Texture.h"
#include "LightEnv.h"
#include "Visual.h"
#include "Model.h"
#include "ModelDef.h"
#include "types.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 ()
{
@ -32,7 +101,8 @@ CRenderer::CRenderer ()
m_Height=0;
m_Depth=0;
m_FrameCounter=0;
m_TerrainMode=FILL;
m_TerrainRenderMode=SOLID;
m_ModelRenderMode=SOLID;
}
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)
{
m_Width = width;
m_Height = height;
m_Depth = depth;
// set packing parameters
glPixelStorei(GL_PACK_ALIGNMENT,1);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
// setup default state
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glClearColor(0.0f,0.0f,0.0f,0.0f);
// query card capabilities
EnumCaps();
return true;
}
@ -72,35 +162,199 @@ void CRenderer::BeginFrame()
// bump frame counter
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
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
void CRenderer::FlushFrame()
{
unsigned i;
// render submitted patches and models
RenderPatches();
// render base terrain
if (m_TerrainMode==WIREFRAME) {
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
RenderModels();
for (i=0;i<m_TerrainPatches.size();++i) {
RenderPatchBase(m_TerrainPatches[i].m_Object);
}
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]);
}
// call on the transparency renderer to render all the transparent stuff
g_TransparencyRenderer.Render();
// empty lists
m_TerrainPatches.clear();
@ -115,7 +369,8 @@ void CRenderer::EndFrame()
void CRenderer::SetCamera(CCamera& camera)
{
CMatrix3D view = camera.m_Orientation.GetTranspose();
CMatrix3D view;
camera.m_Orientation.Invert(view);
CMatrix3D proj = camera.GetProjection();
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();
glViewport (vp.m_X, vp.m_Y, vp.m_Width, vp.m_Height);
m_Camera=camera;
}
void CRenderer::Submit(CPatch* patch)
{
SSubmission<CPatch*> sub;
patch->m_LastVisFrame=m_FrameCounter;
sub.m_Object=patch;
m_TerrainPatches.push_back(sub);
}
void CRenderer::Submit(CModel* model,CMatrix3D* transform)
void CRenderer::Submit(CVisual* visual)
{
SSubmission<CModel*> sub;
sub.m_Object=model;
sub.m_Transform=transform;
SSubmission<CVisual*> sub;
sub.m_Object=visual;
m_Models.push_back(sub);
}
@ -167,74 +422,109 @@ void CRenderer::Submit(COverlay* overlay)
{
}
/*
void CRenderer::RenderTileOutline (CMiniPatch *mpatch)
void CRenderer::RenderPatchSubmissions()
{
glActiveTexture (GL_TEXTURE0);
glDisable (GL_DEPTH_TEST);
glDisable (GL_TEXTURE_2D);
glLineWidth (4);
STerrainVertex V[4];
V[0] = mpatch->m_pVertices[0];
V[1] = mpatch->m_pVertices[1];
V[2] = mpatch->m_pVertices[MAP_SIZE*1 + 1];
V[3] = mpatch->m_pVertices[MAP_SIZE*1];
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);
uint i;
// first ensure all patches have up to date renderdata built for them
for (i=0;i<m_TerrainPatches.size();++i) {
CPatch* patch=m_TerrainPatches[i].m_Object;
CPatchRData* data=(CPatchRData*) patch->m_RenderData;
if (data==0) {
// no renderdata for patch, create it now
data=new CPatchRData(patch);
} else {
data->Update();
}
}
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
bool CRenderer::LoadTexture(CTexture* texture)
{
Handle h=texture->GetHandle();
if (h) {
// already tried to load this texture, nothing to do here - just return accord to whether this
// is a valid handle
// already tried to load this texture, nothing to do here - just return success according
// to whether this is a valid handle or not
return h==0xfffffff ? true : false;
} else {
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
void CRenderer::SetTexture(int unit,CTexture* texture)
void CRenderer::SetTexture(int unit,CTexture* texture,u32 wrapflags)
{
glActiveTexture(GL_TEXTURE0+unit);
if (texture) {
@ -258,6 +548,11 @@ void CRenderer::SetTexture(int unit,CTexture* texture)
if (!h) {
LoadTexture(texture);
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
@ -273,247 +568,147 @@ void CRenderer::SetTexture(int unit,CTexture* texture)
}
}
void CRenderer::RenderPatchBase (CPatch *patch)
bool CRenderer::IsTextureTransparent(CTexture* texture)
{
CMiniPatch *MPatch, *MPCurrent;
float StartU, StartV;
for (int j=0; j<16; j++)
{
for (int i=0; i<16; i++)
{
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;
if (texture) {
Handle h=texture->GetHandle();
if (!h) {
LoadTexture(texture);
h=texture->GetHandle();
if (h!=0xffffffff) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}
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);
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Handle textures[NumAlphaMaps];
int i;
for (int j=0; j<16; j++)
{
for (int i=0; i<16; i++)
{
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 ();
}
for (i=0;i<NumAlphaMaps;i++) {
textures[i]=tex_load(fnames[i]);
if (textures[i] <= 0) {
return false;
}
}
glDisable (GL_BLEND);
glActiveTexture (GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTexture (GL_TEXTURE0);
int base;//=textures[0].width;
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
#include <vector>
#include "res/res.h"
#include "ogl.h"
#include "Camera.h"
#include "Frustum.h"
#include "PatchRData.h"
#include "ModelRData.h"
#include "SHCoeffs.h"
#include "Terrain.h"
// necessary declarations
class CCamera;
class CPatch;
class CModel;
class CVisual;
class CSprite;
class CParticleSys;
class COverlay;
class CMaterial;
class CLightEnv;
class SPatchRData;
class CTexture;
class CTerrain;
// rendering modes
enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
//////////////////////////////////////////////////////////////////////////////////////////
// SSubmission: generalised class representating a submission of objects to renderer
@ -63,8 +74,36 @@ struct SVertex2D
class CRenderer
{
public:
// various enumerations
enum ETerrainMode { WIREFRAME, FILL };
// various enumerations and renderer related constants
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:
// 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
// the call to frame end, as must the object itself
void Submit(CPatch* patch);
void Submit(CModel* model,CMatrix3D* transform);
void Submit(CVisual* visual);
void Submit(CSprite* sprite,CMatrix3D* transform);
void Submit(CParticleSys* psys,CMatrix3D* transform);
void Submit(COverlay* overlay);
#if 0
// basic primitive rendering operations in 2 and 3D; handy for debugging stuff, but also useful in
// editor tools (eg for highlighting specific terrain patches)
// note:
@ -115,30 +153,53 @@ public:
void RenderLineLoop(int len,const SVertex3D* vertices);
void RenderTri(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,
// 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
void SetTerrainMode(ETerrainMode mode) { m_TerrainMode=mode; }
void SetTerrainRenderMode(ERenderMode mode) { m_TerrainRenderMode=mode; }
// 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
bool LoadTexture(CTexture* texture);
// 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
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:
friend class CPatchRData;
friend class CModelRData;
friend class CTransparencyRenderer;
// patch rendering stuff
void RenderPatchBase(CPatch* patch);
void RenderPatchTrans(CPatch* patch);
void RenderPatchSubmissions();
void RenderPatches();
// model rendering stuff
void RenderModel(SSubmission<CModel*>& modelsub);
void BuildTransparentPasses(CVisual* visual);
void RenderModelSubmissions();
void RenderModels();
// RENDERER DATA:
// view width
@ -150,15 +211,40 @@ protected:
// frame counter
int m_FrameCounter;
// 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
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<CParticleSys*> > m_ParticleSyses;
std::vector<SSubmission<COverlay*> > m_Overlays;
// current lighting setup
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"
CSHCoeffs::CSHCoeffs()
{
Clear();
}
void CSHCoeffs::Clear()
{
for (int i=0;i<9;i++) {
_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));
}
void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color)
void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color) const
{
#if 1
color=_data[0];

View File

@ -19,10 +19,12 @@ class CSHCoeffs
public:
CSHCoeffs();
void Clear();
void AddAmbientLight(const RGBColor& color);
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; }

View File

@ -12,18 +12,9 @@
#ifndef TERRGLOBALS_H
#define TERRGLOBALS_H
const int PATCH_SIZE = 16;
const int CELL_SIZE = 4; //horizontal scale of the patches
const float HEIGHT_SCALE = 0.35f;
//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 );
const int PATCH_SIZE = 16;
const int CELL_SIZE = 4; //horizontal scale of the patches
const float HEIGHT_SCALE = 0.35f/256.0f;
#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 "LightEnv.h"
#include "SHCoeffs.h"
bool g_HillShading = true;
CVector3D SeasonLight[2];
float SeasonColor[2][3];
CTerrain::CTerrain ()
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];
if (m_pVertices == NULL)
return false;
// allocate data for new terrain
m_Heightmap=new u16[m_MapSize*m_MapSize];
m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches];
for (j=0; j<MAP_SIZE; j++)
{
for (int i=0; i<MAP_SIZE; i++)
{
int pos = j*MAP_SIZE + i;
m_pVertices[pos].m_Position.X = ((float)i)*CELL_SIZE;
m_pVertices[pos].m_Position.Y = (*data++)*HEIGHT_SCALE;
m_pVertices[pos].m_Position.Z = ((float)j)*CELL_SIZE;
}
// given a heightmap?
if (data) {
// yes; keep a copy of it
memcpy(m_Heightmap,data,m_MapSize*m_MapSize*sizeof(u16));
} else {
// build a flat terrain
memset(m_Heightmap,0,m_MapSize*m_MapSize*sizeof(u16));
}
for (j=0; j<NUM_PATCHES_PER_SIDE; j++)
{
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();
// setup patch parents, indices etc
InitialisePatches();
return true;
}
void CTerrain::CalcLighting(const CLightEnv& lightEnv)
void CTerrain::CalcPosition(u32 i,u32 j,CVector3D& pos)
{
CSHCoeffs coeffs;
coeffs.AddAmbientLight(lightEnv.m_TerrainAmbientColor);
CVector3D dirlight;
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);
}
u16 height=m_Heightmap[j*m_MapSize + i];
pos.X = float(i)*CELL_SIZE;
pos.Y = float(height)*HEIGHT_SCALE;
pos.Z = float(j)*CELL_SIZE;
}
void CTerrain::CalcNormals()
{
CVector3D left, right, up, down, n[4];
void CTerrain::CalcNormal(u32 i,u32 j,CVector3D& normal)
{
CVector3D left, right, up, down;
for (int j=0; j<MAP_SIZE; j++)
{
for (int i=0; i<MAP_SIZE; i++)
{
left.Clear();
right.Clear();
up.Clear();
down.Clear();
if (i>0)
left = m_pVertices[j*MAP_SIZE + i - 1].m_Position -
m_pVertices[j*MAP_SIZE + i].m_Position;
left.Clear();
right.Clear();
up.Clear();
down.Clear();
// get position of vertex where normal is being evaluated
CVector3D basepos;
CalcPosition(i,j,basepos);
if (i<MAP_SIZE-1)
right = m_pVertices[j*MAP_SIZE + i + 1].m_Position -
m_pVertices[j*MAP_SIZE + i].m_Position;
CVector3D tmp;
if (i>0) {
CalcPosition(i-1,j,tmp);
left=tmp-basepos;
}
if (j>0)
up = m_pVertices[(j-1)*MAP_SIZE + i].m_Position -
m_pVertices[j*MAP_SIZE + i].m_Position;
if (i<m_MapSize-1) {
CalcPosition(i+1,j,tmp);
right=tmp-basepos;
}
if (j<MAP_SIZE-1)
down = m_pVertices[(j+1)*MAP_SIZE + i].m_Position -
m_pVertices[j*MAP_SIZE + i].m_Position;
if (j>0) {
CalcPosition(i,j-1,tmp);
up=tmp-basepos;
}
n[0] = up.Cross(left);
n[1] = left.Cross(down);
n[2] = down.Cross(right);
n[3] = right.Cross(up);
if (j<m_MapSize-1) {
CalcPosition(i,j+1,tmp);
down=tmp-basepos;
}
float n0len=n[0].GetLength();
if (n0len>0.0001f) n[0]*=1.0f/n0len;
CVector3D n0 = up.Cross(left);
CVector3D n1 = left.Cross(down);
CVector3D n2 = down.Cross(right);
CVector3D n3 = right.Cross(up);
float n1len=n[1].GetLength();
if (n1len>0.0001f) n[1]*=1.0f/n1len;
normal = n0 + n1 + n2 + n3;
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();
if (n3len>0.0001f) n[3]*=1.0f/n3len;
CPatch* CTerrain::GetPatch(int32 x,int32 z)
{
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];
float nlen=Normal.GetLength();
if (nlen>0.00001f) Normal*=1.0f/nlen;
m_pVertices[j*MAP_SIZE + i].m_Normal=Normal;
CMiniPatch* CTerrain::GetTile(int32 x,int32 z)
{
if (x<0 || x>=int32(m_MapSize)-1) return 0;
if (z<0 || z>=int32(m_MapSize)-1) return 0;
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 ()
{
CPatch *ThisPatch, *RightPatch;
// now build new patches
for (j=0;j<size;j++) {
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++)
{
for (int pi=0; pi<NUM_PATCHES_PER_SIDE; pi++)
{
ThisPatch = &m_Patches[pj][pi];
if (pi < NUM_PATCHES_PER_SIDE-1)
RightPatch = &m_Patches[pj][pi+1];
else
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 (j<m_MapSizePatches && size>m_MapSizePatches) {
// copy over the last tile from each column
for (u32 n=0;n<size-m_MapSizePatches;n++) {
for (int m=0;m<16;m++) {
CMiniPatch& src=m_Patches[j*m_MapSizePatches+m_MapSizePatches-1].m_MiniPatches[m][15];
for (int k=0;k<16;k++) {
CMiniPatch& dst=newPatches[j*size+m_MapSizePatches+n].m_MiniPatches[m][k];
dst.Tex1=src.Tex1;
dst.Tex1Priority=src.Tex1Priority;
}
}
}
}
}
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
#define TERRAIN_H
#include <stdio.h>
#include "Patch.h"
#include "Vector3D.h"
#include "TerrGlobals.h"
class CLightEnv;
class CSHCoeffs;
extern bool g_HillShading;
class CTerrain
{
public:
CTerrain ();
~CTerrain ();
public:
CTerrain();
~CTerrain();
bool Load(char *filename);
bool InitFromHeightmap(const u8* data);
bool Initialize(u32 size,const u16* ptr);
// protected:
//the patches currently loaded
CPatch m_Patches[NUM_PATCHES_PER_SIDE][NUM_PATCHES_PER_SIDE];
STerrainVertex *m_pVertices;
// return number of vertices along edge of the terrain
u32 GetVerticesPerSide() { return m_MapSize; }
// return number of patches along edge of the terrain
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());
CStr pathname("terrains/textures/");
CStr pathname("art/textures/terrain/types/");
pathname+=m_TerrainTextures[type].m_Name;
pathname+='/';
pathname+=filename;
@ -151,7 +151,7 @@ void CTextureManager::LoadTerrainTextures(int terraintype,const char* fileext)
long handle;
// build pathname
CStr pathname("terrains\\textures\\");
CStr pathname("mods\\official\\art\\textures\\terrain\\types\\");
pathname+=m_TerrainTextures[terraintype].m_Name;
pathname+="\\";
@ -181,7 +181,7 @@ void CTextureManager::BuildTerrainTypes()
long handle;
// 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]!='_') {
AddTextureType(file.name);

View File

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

View File

@ -1,14 +1,16 @@
#include "Matrix3D.h"
#include "Renderer.h"
#include "Terrain.h"
#include "Camera.h"
#include "LightEnv.h"
#include "TextureManager.h"
#include "Prometheus.h"
#include "detect.h"
#include "time.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
//#include "win.h" // REMOVEME
@ -37,15 +39,8 @@ double g_LastTime;
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;
void terr_init()
{
int xres,yres;
@ -69,10 +64,10 @@ void terr_update()
g_Renderer.BeginFrame();
g_Renderer.SetCamera(g_Camera);
/////////////////////////////////////////////
/*POINT MousePos;
// switch on wireframe for terrain if we want it
g_Renderer.SetTerrainRenderMode(SOLID);
GetCursorPos (&MousePos);*/
/////////////////////////////////////////////
CVector3D right(1,0,1);
CVector3D up(1,0,-1);
right.Normalize ();
@ -106,22 +101,21 @@ void terr_update()
CFrustum frustum=g_Camera.GetFustum();
// 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)) {
g_Renderer.Submit(&g_Terrain.m_Patches[j][i]);
if (frustum.IsBoxVisible (CVector3D(0,0,0),g_Terrain.GetPatch(j, i)->GetBounds())) {
g_Renderer.Submit(g_Terrain.GetPatch(j, i));
}
}
}
// flush the frame to force terrain to be renderered before overlays
g_Renderer.FlushFrame();
// g_Renderer.RenderTileOutline (&(g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]));
// mark end of frame
g_Renderer.EndFrame();
}
@ -142,11 +136,11 @@ bool terr_handler(const SDL_Event& ev)
case SDL_KEYDOWN:
switch(ev.key.keysym.sym)
{
case 'W':
if (g_Renderer.GetTerrainMode()==CRenderer::WIREFRAME) {
g_Renderer.SetTerrainMode(CRenderer::FILL);
case 'W':
if (g_Renderer.GetTerrainRenderMode()==WIREFRAME) {
g_Renderer.SetTerrainRenderMode(SOLID);
} else {
g_Renderer.SetTerrainMode(CRenderer::WIREFRAME);
g_Renderer.SetTerrainRenderMode(WIREFRAME);
}
break;
@ -158,14 +152,14 @@ bool terr_handler(const SDL_Event& ev)
g_Camera.m_Orientation.Translate (100, 150, -100);
break;
case 'L':
/* case 'L':
g_HillShading = !g_HillShading;
break;
break;*/
// tile selection
case SDLK_DOWN:
if(++SelTX > 15)
if(SelPX == NUM_PATCHES_PER_SIDE-1)
if(SelPX == g_Terrain.GetPatchesPerSide()-1)
SelTX = 15;
else
SelTX = 0, SelPX++;
@ -180,7 +174,7 @@ bool terr_handler(const SDL_Event& ev)
break;
case SDLK_RIGHT:
if(++SelTY > 15)
if(SelPY == NUM_PATCHES_PER_SIDE-1)
if(SelPY == g_Terrain.GetPatchesPerSide()-1)
SelTY = 15;
else
SelTY = 0, SelPY++;
@ -197,8 +191,8 @@ bool terr_handler(const SDL_Event& ev)
case SDLK_KP0:
{
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
if (!MPatch->Tex2)
CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX];
/*if (!MPatch->Tex2)
{
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
MPatch->Tex2 = BaseTexs[g_SecTexCounter];
@ -207,13 +201,13 @@ bool terr_handler(const SDL_Event& ev)
{
MPatch->Tex2 = 0;
MPatch->m_AlphaMap = 0;
}
}*/
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++;
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];
if (MPatch->/*m_pTransitionTexture*/m_AlphaMap)
if (MPatch->m_AlphaMap)
{
g_TransTexCounter++;
if (g_TransTexCounter >= NUM_ALPHA_MAPS)
@ -253,7 +247,7 @@ bool terr_handler(const SDL_Event& ev)
}
break;
}
}*/
}
}
@ -267,32 +261,61 @@ bool terr_handler(const SDL_Event& ev)
void InitScene ()
{
// setup default lighting environment
g_LightEnv.m_SunColor=RGBColor(0.75f,0.70f,0.65f);
g_LightEnv.m_Rotation=270;
g_LightEnv.m_Elevation=DEGTORAD(30);
g_LightEnv.m_TerrainAmbientColor=RGBColor(0.0f,0.0f,0.0f);
g_LightEnv.m_SunColor=RGBColor(1,1,1);
g_LightEnv.m_Rotation=DEGTORAD(270);
g_LightEnv.m_Elevation=DEGTORAD(45);
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");
for (int pj=0; pj<NUM_PATCHES_PER_SIDE; pj++)
// load terrain
Handle ht = tex_load("terrain.raw");
if(ht > 0)
{
for (int pi=0; pi<NUM_PATCHES_PER_SIDE; pi++)
{
for (int tj=0; tj<16; tj++)
{
for (int ti=0; ti<16; ti++)
{
g_Terrain.m_Patches[pj][pi].m_MiniPatches[tj][ti].Tex1 = BaseTexs[0];//rand()%5];
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];
const u8* p;
int w;
int h;
tex_info(ht, &w, &h, NULL, NULL, (void **)&p);
printf("terrain.raw: %dx%d\n", w, h);
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.m_Orientation.SetXRotation(DEGTORAD(30));
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
@ -304,75 +327,29 @@ void InitScene ()
void InitResources()
{
int i;
char* base_fns[] =
{
"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;
#ifndef _WIN32
g_TexMan.AddTextureType("grass");
g_TexMan.AddTexture("Base1.tga", 0);
#else
char* fns[NUM_ALPHA_MAPS] = {
"Transition1.bmp",
"Transition2.bmp",
"Transition3.bmp",
"Transition4.bmp",
"Transition5.bmp",
};
cnt=5;
g_TexMan.LoadTerrainTextures();
#endif
for(i = 0; i < cnt; i++)
{
AlphaMaps[i] = tex_load(fns[i]);
tex_upload(AlphaMaps[i], GL_LINEAR, GL_INTENSITY4);
}
const char* fns[CRenderer::NumAlphaMaps] = {
"art/textures/terrain/alphamaps/special/blendcircle.png",
"art/textures/terrain/alphamaps/special/blendlshape.png",
"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));
}