jedi-academy/code/qcommon/cm_terrainmap.cpp
2013-04-23 15:21:39 +10:00

489 lines
10 KiB
C++

#include "../server/exe_headers.h"
#include "cm_local.h"
#include "cm_patch.h"
#include "cm_landscape.h"
#include "../game/genericparser2.h"
//#include "image.h"
//#include "../qcommon/q_imath.h"
#include "cm_terrainmap.h"
#include "cm_draw.h"
#include "../png/png.h"
static CTerrainMap *TerrainMap = 0;
void R_CreateAutomapImage( const char *name, const byte *pic, int width, int height,
qboolean mipmap, qboolean allowPicmip, qboolean allowTC, int glWrapClampMode );
// simple function for getting a proper color for a side
inline CPixel32 SideColor(int side)
{
CPixel32 col(255,255,255);
switch (side)
{
default:
break;
case SIDE_BLUE:
col = CPixel32(0,0,192);
break;
case SIDE_RED:
col = CPixel32(192,0,0);
break;
}
return col;
}
CTerrainMap::CTerrainMap(CCMLandScape *landscape) :
mLandscape(landscape)
{
ApplyBackground();
ApplyHeightmap();
CDraw32 draw;
draw.SetBuffer((CPixel32*) mImage);
draw.SetBufferSize(TM_WIDTH,TM_HEIGHT,TM_WIDTH);
// create version with paths and water shown
int x,y;
int water;
int land;
for (y=0; y<TM_HEIGHT; y++)
for (x=0; x<TM_WIDTH; x++)
{
CPixel32 cp = ((CPixel32*)mBufImage)[PIXPOS(x,y,TM_WIDTH)];
land = CLAMP(((255 - cp.a)*2)/3,0,255);
water = CLAMP((landscape->GetBaseWaterHeight() - cp.a)*4, 0, 255);
cp.a = 255;
if (x > TM_BORDER && x < (TM_WIDTH-TM_BORDER) &&
y > TM_BORDER && y < (TM_WIDTH-TM_BORDER))
{
cp = ALPHA_PIX (CPixel32(0,0,0), cp, land, 256-land);
if (water > 0)
cp = ALPHA_PIX (CPixel32(0,0,255), cp, water, 256-water);
}
draw.PutPix(x, y, cp);
}
// Load icons for symbols on map
GLenum format;
#ifdef _XBOX
int mipcount;
R_LoadImage("gfx/menus/rmg/start", (byte**)&mSymStart, &mSymStartWidth, &mSymStartHeight, &mipcount, &format);
R_LoadImage("gfx/menus/rmg/end", (byte**)&mSymEnd, &mSymEndWidth, &mSymEndHeight, &mipcount, &format);
R_LoadImage("gfx/menus/rmg/objective", (byte**)&mSymObjective, &mSymObjectiveWidth, &mSymObjectiveHeight, &mipcount, &format);
R_LoadImage("gfx/menus/rmg/building", (byte**)&mSymBld, &mSymBldWidth, &mSymBldHeight, &mipcount, &format);
#else
R_LoadImage("gfx/menus/rmg/start", (byte**)&mSymStart, &mSymStartWidth, &mSymStartHeight, &format);
R_LoadImage("gfx/menus/rmg/end", (byte**)&mSymEnd, &mSymEndWidth, &mSymEndHeight, &format);
R_LoadImage("gfx/menus/rmg/objective", (byte**)&mSymObjective, &mSymObjectiveWidth, &mSymObjectiveHeight, &format);
R_LoadImage("gfx/menus/rmg/building", (byte**)&mSymBld, &mSymBldWidth, &mSymBldHeight, &format);
#endif
}
CTerrainMap::~CTerrainMap()
{
if (mSymStart)
{
Z_Free(mSymStart);
mSymStart = NULL;
}
if (mSymEnd)
{
Z_Free(mSymEnd);
mSymEnd = NULL;
}
if (mSymBld)
{
Z_Free(mSymBld);
mSymBld = NULL;
}
if (mSymObjective)
{
Z_Free(mSymObjective);
mSymObjective = NULL;
}
CDraw32::CleanUp();
}
void CTerrainMap::ApplyBackground(void)
{
int x, y;
byte *outPos;
float xRel, yRel, xInc, yInc;
byte *backgroundImage;
int backgroundWidth, backgroundHeight, backgroundDepth;
int pos;
GLenum format;
memset(mImage, 255, sizeof(mBufImage));
// R_LoadImage("textures\\kamchatka\\ice", &backgroundImage, &backgroundWidth, &backgroundHeight, &format);0
backgroundDepth = 4;
#ifdef _XBOX
int mipcount;
R_LoadImage("gfx\\menus\\rmg\\01_bg", &backgroundImage, &backgroundWidth, &backgroundHeight, &mipcount, &format);
#else
R_LoadImage("gfx\\menus\\rmg\\01_bg", &backgroundImage, &backgroundWidth, &backgroundHeight, &format);
#endif
if (backgroundImage)
{
outPos = (byte *)mBufImage;
xInc = (float)backgroundWidth / (float)TM_WIDTH;
yInc = (float)backgroundHeight / (float)TM_HEIGHT;
yRel = 0.0;
for(y=0;y<TM_HEIGHT;y++)
{
xRel = 0.0;
for(x=0;x<TM_WIDTH;x++)
{
pos = ((((int)yRel)*backgroundWidth) + ((int)xRel)) * 4;
*outPos = backgroundImage[pos++];
outPos++;
*outPos = backgroundImage[pos++];
outPos++;
*outPos = backgroundImage[pos];
outPos+=2;
xRel += xInc;
}
yRel += yInc;
}
Z_Free(backgroundImage);
}
}
void CTerrainMap::ApplyHeightmap(void)
{
int x, y;
byte *inPos = mLandscape->GetHeightMap();
int width = mLandscape->GetRealWidth();
int height = mLandscape->GetRealHeight();
byte *outPos;
unsigned tempColor;
float xRel, yRel, xInc, yInc;
int count;
outPos = (byte *)mBufImage;
outPos += (((TM_BORDER * TM_WIDTH) + TM_BORDER) * 4);
xInc = (float)width / (float)(TM_REAL_WIDTH);
yInc = (float)height / (float)(TM_REAL_HEIGHT);
// add in height map as alpha
yRel = 0.0;
for(y=0;y<TM_REAL_HEIGHT;y++)
{
// x is flipped!
xRel = width;
for(x=0;x<TM_REAL_WIDTH;x++)
{
count = 1;
tempColor = inPos[(((int)yRel)*width) + ((int)xRel)];
if (yRel >= 1.0)
{
tempColor += inPos[(((int)(yRel-0.5))*width) + ((int)xRel)];
count++;
}
if (yRel <= height-2)
{
tempColor += inPos[(((int)(yRel+0.5))*width) + ((int)xRel)];
count++;
}
if (xRel >= 1.0)
{
tempColor += inPos[(((int)(yRel))*width) + ((int)(xRel-0.5))];
count++;
}
if (xRel <= width-2)
{
tempColor += inPos[(((int)(yRel))*width) + ((int)(xRel+0.5))];
count++;
}
tempColor /= count;
outPos[3] = tempColor;
outPos += 4;
// x is flipped!
xRel -= xInc;
}
outPos += TM_BORDER * 4 * 2;
yRel += yInc;
}
}
// Convert position in game coords to automap coords
void CTerrainMap::ConvertPos(int& x, int& y)
{
x = ((x - mLandscape->GetMins()[0]) / mLandscape->GetSize()[0]) * TM_REAL_WIDTH;
y = ((y - mLandscape->GetMins()[1]) / mLandscape->GetSize()[1]) * TM_REAL_HEIGHT;
// x is flipped!
x = TM_REAL_WIDTH - x - 1;
// border
x += TM_BORDER;
y += TM_BORDER;
}
void CTerrainMap::AddStart(int x, int y, int side)
{
ConvertPos(x, y);
CDraw32 draw;
draw.BlitColor(x-mSymStartWidth/2, y-mSymStartHeight/2, mSymStartWidth, mSymStartHeight,
(CPixel32*)mSymStart, 0, 0, mSymStartWidth, SideColor(side));
}
void CTerrainMap::AddEnd(int x, int y, int side)
{
ConvertPos(x, y);
CDraw32 draw;
draw.BlitColor(x-mSymEndWidth/2, y-mSymEndHeight/2, mSymEndWidth, mSymEndHeight,
(CPixel32*)mSymEnd, 0, 0, mSymEndWidth, SideColor(side));
}
void CTerrainMap::AddObjective(int x, int y, int side)
{
ConvertPos(x, y);
CDraw32 draw;
draw.BlitColor(x-mSymObjectiveWidth/2, y-mSymObjectiveHeight/2, mSymObjectiveWidth, mSymObjectiveHeight,
(CPixel32*)mSymObjective, 0, 0, mSymObjectiveWidth, SideColor(side));
}
void CTerrainMap::AddBuilding(int x, int y, int side)
{
ConvertPos(x, y);
CDraw32 draw;
draw.BlitColor(x-mSymBldWidth/2, y-mSymBldHeight/2, mSymBldWidth, mSymBldHeight,
(CPixel32*)mSymBld, 0, 0, mSymBldWidth, SideColor(side));
}
void CTerrainMap::AddNPC(int x, int y, bool friendly)
{
ConvertPos(x, y);
CDraw32 draw;
if (friendly)
draw.DrawCircle(x,y,3, CPixel32(0,192,0), CPixel32(0,0,0,0));
else
draw.DrawCircle(x,y,3, CPixel32(192,0,0), CPixel32(0,0,0,0));
}
void CTerrainMap::AddNode(int x, int y)
{
ConvertPos(x, y);
CDraw32 draw;
draw.DrawCircle(x,y,20, CPixel32(255,255,255), CPixel32(0,0,0,0));
}
void CTerrainMap::AddWallRect(int x, int y, int side)
{
ConvertPos(x, y);
CDraw32 draw;
switch (side)
{
default:
draw.DrawBox(x-1,y-1,3,3,CPixel32(192,192,192,128));
break;
case SIDE_BLUE:
draw.DrawBox(x-1,y-1,3,3,CPixel32(0,0,192,128));
break;
case SIDE_RED:
draw.DrawBox(x-1,y-1,3,3,CPixel32(192,0,0,128));
break;
}
}
void CTerrainMap::AddPlayer(vec3_t origin, vec3_t angles)
{
// draw player start on automap
CDraw32 draw;
vec3_t up;
vec3_t pt[4] = {{0,0,0},{-5,-5,0},{10,0,0},{-5,5,0}};
vec3_t p;
int x,y,i;
float facing;
POINT poly[4];
facing = angles[1];
up[0] = 0;
up[1] = 0;
up[2] = 1;
x = (int)origin[0];
y = (int)origin[1];
ConvertPos(x, y);
x++; y++;
for (i=0; i<4; i++)
{
RotatePointAroundVector( p, up, pt[i], facing );
poly[i].x = (int)(-p[0] + x);
poly[i].y = (int)(p[1] + y);
}
// draw arrowhead shadow
draw.DrawPolygon(4, poly, CPixel32(0,0,0,128), CPixel32(0,0,0,128));
// draw arrowhead
for (i=0; i<4; i++)
{
poly[i].x--;
poly[i].y--;
}
draw.DrawPolygon(4, poly, CPixel32(255,255,255), CPixel32(255,255,255));
}
void CTerrainMap::Upload(vec3_t player_origin, vec3_t player_angles)
{
CDraw32 draw;
// copy completed map to mBufImage
draw.SetBuffer((CPixel32*) mBufImage);
draw.SetBufferSize(TM_WIDTH,TM_HEIGHT,TM_WIDTH);
draw.Blit(0, 0, TM_WIDTH, TM_HEIGHT,
(CPixel32*)mImage, 0, 0, TM_WIDTH);
// now draw player's location on map
if (player_origin)
{
AddPlayer(player_origin, player_angles);
}
draw.SetAlphaBuffer(255);
R_CreateAutomapImage("*automap", (unsigned char *)draw.buffer, TM_WIDTH, TM_HEIGHT, qfalse, qfalse, qtrue, qfalse);
draw.SetBuffer((CPixel32*) mImage);
}
void CTerrainMap::SaveImageToDisk(const char * terrainName, const char * missionName, const char * seed)
{
//ri.COM_SavePNG(va("save/%s_%s_%s.png", terrainName, missionName, seed),
// (unsigned char *)mImage, TM_WIDTH, TM_HEIGHT, 4);
//rww - Use JPG here? This function seems to be only for debugging anyway.
// PNG_Save(va("save/%s_%s_%s.png", terrainName, missionName, seed),
// (unsigned char *)mImage, TM_WIDTH, TM_HEIGHT, 4);
}
void CM_TM_Create(CCMLandScape *landscape)
{
if (TerrainMap)
{
CM_TM_Free();
}
TerrainMap = new CTerrainMap(landscape);
}
void CM_TM_Free(void)
{
if (TerrainMap)
{
delete TerrainMap;
TerrainMap = 0;
}
}
void CM_TM_AddStart(int x, int y, int side)
{
if (TerrainMap)
{
TerrainMap->AddStart(x, y, side);
}
}
void CM_TM_AddEnd(int x, int y, int side)
{
if (TerrainMap)
{
TerrainMap->AddEnd(x, y, side);
}
}
void CM_TM_AddObjective(int x, int y, int side)
{
if (TerrainMap)
{
TerrainMap->AddObjective(x, y, side);
}
}
void CM_TM_AddNPC(int x, int y, bool friendly)
{
if (TerrainMap)
{
TerrainMap->AddNPC(x, y, friendly);
}
}
void CM_TM_AddNode(int x, int y)
{
if (TerrainMap)
{
TerrainMap->AddNode(x, y);
}
}
void CM_TM_AddBuilding(int x, int y, int side)
{
if (TerrainMap)
{
TerrainMap->AddBuilding(x, y, side);
}
}
void CM_TM_AddWallRect(int x, int y, int side)
{
if (TerrainMap)
{
TerrainMap->AddWallRect(x, y, side);
}
}
void CM_TM_Upload(vec3_t player_origin, vec3_t player_angles)
{
if (TerrainMap)
{
TerrainMap->Upload(player_origin, player_angles);
}
}
void CM_TM_SaveImageToDisk(const char * terrainName, const char * missionName, const char * seed)
{
if (TerrainMap)
{ // write out automap
TerrainMap->SaveImageToDisk(terrainName, missionName, seed);
}
}
void CM_TM_ConvertPosition(int &x, int &y, int Width, int Height)
{
if (TerrainMap)
{
TerrainMap->ConvertPos(x, y);
x = x * Width / TM_WIDTH;
y = y * Height / TM_HEIGHT;
}
}