fteqw/plugins/terrorgen/terragen.c

139 lines
4.5 KiB
C

/*
mod_terrain_create terrorgen; edit maps/terrorgen.hmp; map terrorgen
you can use mod_terrain_convert to generate+save the entire map for redistribution to people without this particular plugin version, ensuring longevity.
(this paticular command was meant to load+save the entire map, once mod_terrain_savever 2 is default...)
FIXME: no way to speciffy which gen plugin to use for a particular map
*/
#include "../plugin.h"
#include "glquake.h"
#include "com_mesh.h"
#include "gl_terrain.h"
static terrainfuncs_t *terr;
static modplugfuncs_t *modfuncs;
static void TerrorGen_GenerateOne(heightmap_t *hm, int sx, int sy, hmsection_t *s)
{
int x,y,i;
qbyte *lm;
s->flags |= TSF_RELIGHT;
//pick the textures to blend between. I'm just hardcoding shit here. this is meant to be some sort example.
Q_strlcpy(s->texname[0], "city4_2", sizeof(s->texname[0]));
Q_strlcpy(s->texname[1], "ground1_2", sizeof(s->texname[1]));
Q_strlcpy(s->texname[2], "ground1_8", sizeof(s->texname[2]));
Q_strlcpy(s->texname[3], "ground1_1", sizeof(s->texname[3]));
for (y = 0, i=0; y < SECTHEIGHTSIZE; y++)
for (x = 0; x < SECTHEIGHTSIZE; x++, i++)
{
//calculate where it is in worldspace, if that's useful to you.
float wx = hm->sectionsize*(sx + x/(float)(SECTHEIGHTSIZE-1));
float wy = hm->sectionsize*(sy + y/(float)(SECTHEIGHTSIZE-1));
//many shallow mounds, on a grid.
s->heights[i] = 128*sin(wx * (2*M_PI/1024)) * sin(wy * (2*M_PI/1024));
//calculate the RGBA tint. these are floats, so you can oversaturate.
s->colours[i][0] = 1;
s->colours[i][1] = 1;
s->colours[i][2] = 1;
s->colours[i][3] = 1;
}
//make sure there's lightmap storage available
terr->InitLightmap(s, /*fill with default values*/true);
lm = terr->GetLightmap(s, 0, /*flag as edited*/true);
if (lm)
{ //pleaseworkpleaseworkpleasework
for (y = 0; y < SECTTEXSIZE; y++, lm += (HMLMSTRIDE)*4)
for (x = 0; x < SECTTEXSIZE; x++)
{
//calculate where it is in worldspace, if that's useful to you.
float wx = hm->sectionsize*(sx + x/(float)(SECTTEXSIZE-1));
float wy = hm->sectionsize*(sy + y/(float)(SECTTEXSIZE-1));
//calc which texture to use
//adds to 1, with texture[3] taking the remainder.
lm[x*4+0] = max(0, 255 - 255*fabs(wx/1024));
lm[x*4+1] = max(0, 255 - 255*fabs(wy/1024));
lm[x*4+2] = min(lm[x*4+0],lm[x*4+1]);
lm[x*4+0] -= lm[x*4+2];
lm[x*4+1] -= lm[x*4+2];
//logically: lm[x*4+3] = 255-(lm[x*4+0]+lm[x*4+1]+lm[x*4+2]);
//however, the fourth channel is actually used as a lighting multiplier.
lm[x*4+3] = 255;
}
}
//insert the occasional mesh...
if ((sx&3) == 0 && (sy&3) == 0)
{
vec3_t ang, org, axis[3];
org[0] = hm->sectionsize*sx;
org[1] = hm->sectionsize*sy;
org[2] = 128;
VectorClear(ang);
ang[0] = sy*12.5; //lul
ang[1] = sx*12.5;
modfuncs->AngleVectors(ang, axis[0], axis[1], axis[2]);
VectorNegate(axis[1],axis[1]); //axis[1] needs to be left, not right. silly quakeisms.
//obviously you can insert mdls instead... preferably do that!
terr->AddMesh(hm, TGS_TRYLOAD, NULL, "maps/dm4.bsp", org, axis, 1);
}
}
#define GENBLOCKSIZE 1
static qboolean QDECL TerrorGen_GenerateBlock(heightmap_t *hm, int sx, int sy, unsigned int tgsflags)
{
hmsection_t *sect[GENBLOCKSIZE*GENBLOCKSIZE];
int mx = sx & ~(GENBLOCKSIZE-1);
int my = sy & ~(GENBLOCKSIZE-1);
if (!terr->GenerateSections(hm, mx, my, GENBLOCKSIZE, sect))
return false;
for (sy = 0; sy < GENBLOCKSIZE; sy++)
{
for (sx = 0; sx < GENBLOCKSIZE; sx++)
{
if (!sect[sx + sy*GENBLOCKSIZE])
continue; //already in memory.
TerrorGen_GenerateOne(hm, mx+sx-CHUNKBIAS, my+sy-CHUNKBIAS, sect[sx + sy*GENBLOCKSIZE]);
terr->FinishedSection(sect[sx + sy*GENBLOCKSIZE], true);
}
}
return true;
}
static qintptr_t TerrorGen_Shutdown(qintptr_t *args)
{ //if its still us, make sure there's no dangling pointers.
if (terr->AutogenerateSection == TerrorGen_GenerateBlock)
terr->AutogenerateSection = NULL;
return true;
}
qintptr_t Plug_Init(qintptr_t *args)
{
if (CHECKBUILTIN(Mod_GetPluginModelFuncs))
{
modfuncs = pMod_GetPluginModelFuncs(sizeof(modplugfuncs_t));
if (modfuncs && modfuncs->version < MODPLUGFUNCS_VERSION)
modfuncs = NULL;
}
if (modfuncs && modfuncs->GetTerrainFuncs)
terr = modfuncs->GetTerrainFuncs();
if (!terr)
return false;
if (!Plug_Export("Shutdown", TerrorGen_Shutdown))
return false;
terr->AutogenerateSection = TerrorGen_GenerateBlock;
return true;
}