gtkradiant/contrib/gtkgensurf/gensurf.cpp

468 lines
17 KiB
C++

/*
GenSurf plugin for GtkRadiant
Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
/*
#include <string.h>
#include <tchar.h>
#include <math.h>
*/
#include "gensurf.h"
char gszAppDir[NAME_MAX];
char gszCaption[64];
char gszIni[NAME_MAX];
char gszHelpFile[NAME_MAX];
char gszMapFile[NAME_MAX];
char gszVersion[64];
double Amplitude;
double Roughness;
double TexOffset[2];
double TexScale[2];
double WaveLength;
double Hll, Hur, Vll, Vur;
double Z00, Z01, Z10, Z11;
ELEMENT Vertex[(MAX_ROWS+1)*(MAX_ROWS+1)];
int AddHints;
int ArghRad2;
int AutoOverwrite;
int Decimate=0;
int SnapToGrid=0; // 0, or the grid size to snap to. // Hydra : snap to grid
int FileAppend=0;
int FixBorders;
int HideBackFaces=0;
int NH, NV;
int NumVerticesSelected;
int Plane;
int Preview;
int RandomSeed=1;
int Skybox;
int UseDetail;
int UseLadder;
int VertexMode=0;
int WaveType;
int gNumNodes=0;
int gNumTris=0;
int vid_x, vid_y;
int view_x, view_y;
int view_cx, view_cy;
int UsePatches;
int SlantAngle;
int GimpHints;
int Antialiasing; // ^Fishman - Antializing for the preview window.
int AddTerrainKey; // ^Fishman - Add terrain key to func_group.
int SP; // ^Fishman - Snap to grid.
GtkWidget *g_pWnd; // ghwnd;
GtkWidget *g_pRadiantWnd; // ghwnd_main;
/*HWND ghwndAngles;
*/GtkWidget *g_pWndPreview;
GtkWidget *g_pPreviewWidget;
MYBITMAP gbmp;
NODE *gNode=(NODE *)NULL;
TRI *gTri=(TRI *)NULL;
int Game;
bounding_box PlayerBox[NUMGAMES] = { {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Quake2
{{-16., 16.}, {-16., 16.}, {-36., 36.}}, // Half-Life
{{-16., 16.}, {-16., 16.}, {-32., 32.}}, // SiN
{{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Heretic2 (guess)
{{-16., 16.}, {-16., 16.}, {-24., 32.}}, // KingPin (guess)
{{-30., 30.}, {-30., 30.}, {-10.,160.}}, // Genesis3D (no idea)
{{-16., 16.}, {-16., 16.}, {-24., 32.}}}; // Quake3 (not sure)
//char gszOutputDir[NUMGAMES][NAME_MAX];
//char gszTextureDir[NUMGAMES][NAME_MAX];
char Texture[NUMGAMES][3][64];
//char pakfile[NUMGAMES][NAME_MAX];
//char lastpakfile[NUMGAMES][NAME_MAX];
//int UsePak[NUMGAMES];
//char GameDir[NUMGAMES][NAME_MAX];
char GameName[NUMGAMES][16] = {"Quake2", "Half-Life", "SiN", "Heretic2", "Kingpin", "Genesis3D", "Quake3" };
bool GenSurfInit ()
{
strcpy (gszVersion, "1.05");
strcpy (gszCaption, "GtkGenSurf");
if (strlen (gszVersion))
{
strcat (gszCaption, " v");
strcat (gszCaption, gszVersion);
}
strcpy (gszIni, g_FuncTable.m_pfnProfileGetDirectory ());
strcat (gszIni, "gensurf.ini");
/*if (g_FuncTable.m_pfnReadProjectKey != NULL)
{
char *basepath;
basepath = g_FuncTable.m_pfnReadProjectKey("basepath");
if (basepath)
{
g_strdown (basepath);
if (strstr(basepath,"baseq3"))
Game = QUAKE3;
else if (strstr (basepath,"baseq2"))
Game = QUAKE2;
else // Gotta have a game, might as well be Quake3
Game = QUAKE3;
}
else
Game = QUAKE3;
}
else */
Game = QUAKE3;
ReadIniFile (gszIni);
if (g_pWnd == NULL)
g_pWnd = create_main_dialog ();
return true;
}
// Reads default values
#define OPTS_SECTION "Options"
void ReadIniFile (const char *file)
{
char *Text;
float x1,x2,x3,x4;
int i;
Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Amplitude", "");
if (strlen (Text))
Amplitude = atof (Text);
else
Amplitude = 128;
Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Roughness", "");
if (strlen (Text))
Roughness = atof (Text);
else
Roughness = 16;
Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "WaveLength", "");
if (strlen (Text))
WaveLength = atof (Text);
else
WaveLength = 1024;
Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Extents", "");
if (strlen (Text))
{
sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4);
Hll = x1;
Vll = x2;
Hur = x3;
Vur = x4;
}
else
{
Hll = -512;
Vll = -512;
Hur = 512;
Vur = 512;
}
Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "CornerValues", "");
if (strlen (Text))
{
sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4);
Z00 = x1;
Z01 = x2;
Z10 = x3;
Z11 = x4;
}
else
{
Z00 = 0.;
Z01 = 0.;
Z10 = 0.;
Z11 = 0.;
}
Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "TextureOffset", "");
if (strlen (Text))
{
sscanf(Text,"%f,%f",&x1,&x2);
TexOffset[0] = x1;
TexOffset[1] = x2;
}
else
{
TexOffset[0] = 0.;
TexOffset[1] = 0.;
}
Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION,"TextureScale","");
if (strlen (Text))
{
sscanf(Text,"%f,%f",&x1,&x2);
TexScale[0] = x1;
TexScale[1] = x2;
if(TexScale[0] == 0.) TexScale[0] = 1.0;
if(TexScale[1] == 0.) TexScale[1] = 1.0;
}
else
{
TexScale[0] = 1.;
TexScale[1] = 1.;
}
NH = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NH",8);
NH = max(1,min(NH,MAX_ROWS));
NV = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NV",8);
NV = max(1,min(NV,MAX_ROWS));
// Decimate = GetPrivateProfileInt(OPTS_SECTION,"Decimate",0,file);
// Decimate = max(0,min(Decimate,100));
AddHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddHints",0);
ArghRad2 = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"ArghRad2",0);
AutoOverwrite = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AutoOverwrite",0);
FixBorders = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"FixBorders",1);
HideBackFaces = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"HideBackFaces",0);
Plane = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Plane",0);
Preview = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Preview", 0);
Antialiasing = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Antialiasing",0); // ^Fishman - Antializing for the preview window.
RandomSeed = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"RandomSeed",1);
Skybox = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Skybox",0);
UseDetail = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseDetail",0);
AddTerrainKey = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddTerrainKey",0); // ^Fishman - Add terrain key to func_group.
UseLadder = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseLadder",0);
WaveType = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"WaveType",0);
vid_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_x", 0);
vid_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_y", 0);
view_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_x",0);
view_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_y",0);
view_cx = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cx",0);
view_cy = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cy",0);
UsePatches = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UsePatches",0);
SlantAngle = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"SlantAngle",60);
GimpHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"GimpHints",0);
for(i=0; i<NUMGAMES; i++)
{
// strcpy (gszOutputDir[i], g_FuncTable.m_pfnProfileLoadString (file, GameName[i],"OutputDir",""));
strcpy (Texture[i][0], g_FuncTable.m_pfnProfileLoadString (file, GameName[i], "Texture", ""));
strcpy (Texture[i][1], g_FuncTable.m_pfnProfileLoadString (file, GameName[i], "Texture2", ""));
strcpy (Texture[i][2], g_FuncTable.m_pfnProfileLoadString (file, GameName[i], "Texture3", ""));
// strcpy (gszTextureDir[i], g_FuncTable.m_pfnProfileLoadString (file, GameName[i],"TextureDir",""));
// UsePak[i] = GetPrivateProfileInt(GameName[i],"UsePak",0);
// strcpy (pakfile[i], g_FuncTable.m_pfnProfileLoadString (file, GameName[i],"PakFile",""));
// strcpy (lastpakfile[i], g_FuncTable.m_pfnProfileLoadString (file, GameName[i],"LastPakFile",""));
// strcpy (GameDir[i], g_FuncTable.m_pfnProfileLoadString (file, GameName[i],"GameDir","\0"));
}
/*
if(!strlen(gszTextureDir[QUAKE2]))
strcpy(gszTextureDir[QUAKE2],"c:\\quake2\\baseq2\\textures\\");
if(!strlen(gszTextureDir[KINGPIN]))
strcpy(gszTextureDir[KINGPIN],"c:\\kingpin\\main\\textures\\");
*/
if(!strlen(Texture[QUAKE2][0])) strcpy(Texture[QUAKE2][0], "textures/e1u1/grass1_4");
if(!strlen(Texture[HALFLIFE][0])) strcpy(Texture[HALFLIFE][0], "textures/OUT_GRND1");
if(!strlen(Texture[SIN][0])) strcpy(Texture[SIN][0], "textures/generic/floor_organic/fl_grass");
if(!strlen(Texture[HERETIC2][0])) strcpy(Texture[HERETIC2][0], "textures/canyon/canyon05");
if(!strlen(Texture[KINGPIN][0])) strcpy(Texture[KINGPIN][0], "textures/bricks/s_sr_m3");
if(!strlen(Texture[GENESIS3D][0])) strcpy(Texture[GENESIS3D][0],"textures/rock13");
if(!strlen(Texture[QUAKE3][0])) strcpy(Texture[QUAKE3][0], "textures/organics/grass3");
if(!strlen(Texture[QUAKE3][1])) strcpy(Texture[QUAKE3][1], "textures/common/caulk");
strcpy (gbmp.name, g_FuncTable.m_pfnProfileLoadString (file, "Bitmap","Filename",""));
if (strlen(gbmp.name))
OpenBitmap ();
strcpy (gbmp.defpath, g_FuncTable.m_pfnProfileLoadString (file, "Bitmap","DefaultPath",""));
Text = g_FuncTable.m_pfnProfileLoadString (file, "Bitmap","BlackValue","");
if (strlen (Text))
gbmp.black_value = atof (Text);
else
gbmp.black_value = 0;
Text = g_FuncTable.m_pfnProfileLoadString (file, "Bitmap","WhiteValue","");
if (strlen (Text))
gbmp.white_value = atof (Text);
else
gbmp.white_value = 256.;
}
/*
============
va
does a varargs printf into a temp buffer, so I don't need to have
varargs versions of all text functions.
FIXME: make this buffer size safe someday
============
*/
char *va (char *format, ...)
{
va_list argptr;
static char string[1024];
va_start (argptr, format);
vsprintf (string, format,argptr);
va_end (argptr);
return string;
}
// Writes current values to INI file
void WriteIniFile(const char *file)
{
int i;
g_FuncTable.m_pfnProfileSaveString (file, OPTS_SECTION, "Amplitude", va("%g",Amplitude));
g_FuncTable.m_pfnProfileSaveString (file, OPTS_SECTION, "Roughness", va("%g",Roughness));
g_FuncTable.m_pfnProfileSaveString (file, OPTS_SECTION, "WaveLength", va("%g",WaveLength));
g_FuncTable.m_pfnProfileSaveString (file, OPTS_SECTION, "Extents", va("%g,%g,%g,%g",Hll,Vll,Hur,Vur));
g_FuncTable.m_pfnProfileSaveString (file, OPTS_SECTION, "CornerValues", va("%g,%g,%g,%g",Z00,Z01,Z10,Z11));
g_FuncTable.m_pfnProfileSaveString (file, OPTS_SECTION, "TextureOffset",va("%g,%g",TexOffset[0],TexOffset[1]));
g_FuncTable.m_pfnProfileSaveString (file, OPTS_SECTION, "TextureScale", va("%g,%g",TexScale[0],TexScale[1]));
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "NH", NH);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "NV", NV);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "AddHints", AddHints);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "ArghRad2", ArghRad2);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "AutoOverwrite", AutoOverwrite);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "FixBorders", FixBorders);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "Plane", Plane);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "Preview", Preview);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "Antialiasing", Antialiasing); // ^Fishman - Antializing for the preview window.
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "RandomSeed", RandomSeed);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "Skybox", Skybox);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "UseDetail", UseDetail);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "AddTerrainKey", AddTerrainKey); // ^Fishman - Add terrain key to func_group.
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "UseLadder", UseLadder);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "WaveType", WaveType);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "vid_x", vid_x);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "vid_y", vid_y);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "view_x", view_x);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "view_y", view_y);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "view_cx", view_cx);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "view_cy", view_cy);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "UsePatches", UsePatches);
g_FuncTable.m_pfnProfileSaveInt (file, OPTS_SECTION, "SlantAngle", SlantAngle);
for(i=0; i<NUMGAMES; i++)
{
g_FuncTable.m_pfnProfileSaveString (file, GameName[i], "Texture", Texture[i][0] );
g_FuncTable.m_pfnProfileSaveString (file, GameName[i], "Texture2", Texture[i][1] );
g_FuncTable.m_pfnProfileSaveString (file, GameName[i], "Texture3", Texture[i][2] );
}
g_FuncTable.m_pfnProfileSaveString (file, "Bitmap", "Filename", gbmp.name );
g_FuncTable.m_pfnProfileSaveString (file, "Bitmap", "DefaultPath", gbmp.defpath );
g_FuncTable.m_pfnProfileSaveString (file, "Bitmap", "BlackValue", va("%g",gbmp.black_value));
g_FuncTable.m_pfnProfileSaveString (file, "Bitmap", "WhiteValue", va("%g",gbmp.white_value));
//g_FuncTable.m_pfnProfileSaveString (file, "Formula", "Formula", ExcelFunc );
}
void UpdatePreview (bool DataChange)
{
if (g_pWndPreview && GTK_WIDGET_VISIBLE (g_pWndPreview))
{
if (DataChange)
GenerateXYZ ();
gtk_widget_draw (g_pPreviewWidget, NULL);
}
}
void SaveSetup (GtkWidget *parent)
{
const char *name = g_FuncTable.m_pfnFileDialog (parent, false, "Save GenSurf Settings",
g_FuncTable.m_pfnProfileGetDirectory ());
if (name != NULL)
{
char key[32], text[32];
int i, j;
WriteIniFile (name);
g_FuncTable.m_pfnProfileSaveString (name, OPTS_SECTION,"MapFile",gszMapFile);
sprintf(text,"0x%04x",FileAppend);
g_FuncTable.m_pfnProfileSaveString (name, OPTS_SECTION,"Append",text);
sprintf(text,"0x%04x",Decimate);
g_FuncTable.m_pfnProfileSaveString (name, OPTS_SECTION,"Decimate",text);
for(i=0; i<=NH; i++)
{
for(j=0; j<=NV; j++)
{
if(xyz[i][j].fixed)
{
sprintf(key,"I%dJ%d",i,j);
sprintf(text,"%g %g %g", xyz[i][j].fixed_value, xyz[i][j].range, xyz[i][j].rate);
g_FuncTable.m_pfnProfileSaveString (name, "FixedPoints",key,text);
}
}
}
}
}
void OpenSetup (GtkWidget *parent, int UseDefaults)
{
const char *name;
char key[32], *text;
float value,range,rate;
int i, j;
if (UseDefaults)
name = g_strdup ("plugins/defaults.srf"); // dummy string
else
name = g_FuncTable.m_pfnFileDialog (parent, true, "Open GenSurf Settings",
g_FuncTable.m_pfnProfileGetDirectory ());
if(name != NULL)
{
ReadIniFile (name);
Decimate = g_FuncTable.m_pfnProfileLoadInt (name, OPTS_SECTION,"Decimate",0);
Decimate = max(0,min(Decimate,100));
for (i=0; i<=NH; i++)
{
for (j=0; j<=NV; j++)
{
sprintf(key,"I%dJ%d",i,j);
text = g_FuncTable.m_pfnProfileLoadString (name, "FixedPoints", key, "");
if (strlen (text))
{
xyz[i][j].fixed = 1;
xyz[i][j].rate = 0.;
sscanf(text,"%g %g %g",&value,&range,&rate);
xyz[i][j].fixed_value = value;
xyz[i][j].range = range;
xyz[i][j].rate = rate;
}
else
xyz[i][j].fixed = 0;
}
}
}
}