Added screensapce decal system and stamp placement system in Radiant.

This commit is contained in:
Justin Marshall
2026-05-22 07:54:36 -07:00
parent e8ea0567b0
commit f2e8b0b45e
13 changed files with 962 additions and 32 deletions
+200 -5
View File
@@ -31,6 +31,7 @@ If you have questions concerning this license or the applicable additional terms
#include "qe3.h"
#include "Radiant.h"
#include "EditorMap.h"
#include "XYWnd.h"
#include "CamWnd.h"
#include "OutlinerDlg.h"
@@ -118,6 +119,52 @@ struct cameraNavState_t {
static cameraNavConfig_t s_cameraNavConfig;
static cameraNavState_t s_cameraNavState;
static void CameraNav_GetIniPath(char* path, int pathSize);
static bool CamWnd_DecalPlacementEnabled() {
char iniPath[MAX_PATH];
CameraNav_GetIniPath(iniPath, sizeof(iniPath));
return GetPrivateProfileInt("decals", "enabled", 0, iniPath) != 0;
}
static float CamWnd_DecalFloat(const char* key, const char* defaultValue) {
char iniPath[MAX_PATH];
char value[64];
CameraNav_GetIniPath(iniPath, sizeof(iniPath));
GetPrivateProfileString("decals", key, defaultValue, value, sizeof(value), iniPath);
return (float)atof(value);
}
static void CamWnd_DecalMaterial(idStr& material) {
const char* selected = g_qeglobals.d_texturewin.texdef.name;
if (selected && selected[0] && selected[0] != '(') {
material = selected;
return;
}
material = "textures/decals/default";
}
static void CamWnd_DecalColorFromSelectedMaterial(const idStr& material, idVec4& color) {
color.Set(
CamWnd_DecalFloat("red", "1"),
CamWnd_DecalFloat("green", "1"),
CamWnd_DecalFloat("blue", "1"),
CamWnd_DecalFloat("alpha", "1"));
const idMaterial* mat = declManager->FindMaterial(material.c_str());
if (mat) {
#ifndef QUAKE4
decalInfo_t decalInfo = mat->GetDecalInfo();
color.x *= decalInfo.start[0];
color.y *= decalInfo.start[1];
color.z *= decalInfo.start[2];
color.w *= decalInfo.start[3];
#endif
if (mat->GetEditorImage()) {
mat->GetEditorImage()->Bind();
}
}
}
static void CameraNav_GetIniPath(char* path, int pathSize) {
if (pathSize <= 0) {
@@ -1010,6 +1057,7 @@ static const char* CAMWND_PROP_RENDER_MODE = "QER_CamWnd_RenderMode";
static const char* CAMWND_PROP_REBUILD_MODE = "QER_CamWnd_RebuildMode";
static const char* CAMWND_PROP_ENTITY_MODE = "QER_CamWnd_EntityMode";
static const char* CAMWND_PROP_FILTER_MASK = "QER_CamWnd_FilterMask";
static const char* CAMWND_PROP_DECAL_EDITING = "QER_CamWnd_DecalEditing";
#define CAMWND_CAPTION_HEIGHT 30
#define CAMWND_MENU_HEIGHT 22
@@ -1025,6 +1073,7 @@ static const char* CAMWND_PROP_FILTER_MASK = "QER_CamWnd_FilterMask";
#define CAMWND_MENU_CMD_SHOW_TARGET_LINES 62107
#define CAMWND_MENU_CMD_SHOW_TRIGGER_BRUSHES 62108
#define CAMWND_MENU_CMD_CUBIC_CLIPPING 62109
#define CAMWND_MENU_CMD_DECAL_EDITING 62110
#define CAMWND_FILTER_HIDE_WORLD 0x00000001
#define CAMWND_FILTER_HIDE_PATCHES 0x00000002
@@ -1120,15 +1169,19 @@ static void CamWnd_GetMenuItemRect(HWND hWnd, int item, RECT& rect) {
rect.left = 4;
rect.right = 86;
}
else {
else if (item == 1) {
rect.left = 86;
rect.right = 156;
}
else {
rect.left = 156;
rect.right = 236;
}
}
static int CamWnd_MenuHitTest(HWND hWnd, int x, int y) {
RECT rect;
for (int i = 0; i < 2; i++) {
for (int i = 0; i < 3; i++) {
CamWnd_GetMenuItemRect(hWnd, i, rect);
if (x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom) {
return i;
@@ -1179,6 +1232,25 @@ static void CamWnd_ToggleRealtimeLighting(CCamWnd* cam) {
CamWnd_SetRealtimeLighting(cam, !CamWnd_RealtimeLightingEnabled(cam));
}
static bool CamWnd_DecalEditingEnabled(CCamWnd* cam) {
if (!cam || !cam->GetSafeHwnd()) {
return false;
}
return CamWnd_GetIntProp(cam->GetSafeHwnd(), CAMWND_PROP_DECAL_EDITING, CamWnd_DecalPlacementEnabled() ? 1 : 0) != 0;
}
static void CamWnd_SetDecalEditing(CCamWnd* cam, bool enabled) {
if (!cam || !cam->GetSafeHwnd()) {
return;
}
CamWnd_SetIntProp(cam->GetSafeHwnd(), CAMWND_PROP_DECAL_EDITING, enabled ? 1 : 0);
CamWnd_RequestRedraw(cam);
}
static void CamWnd_ToggleDecalEditing(CCamWnd* cam) {
CamWnd_SetDecalEditing(cam, !CamWnd_DecalEditingEnabled(cam));
}
static void CamWnd_ToggleFilterBit(CCamWnd* cam, int bit) {
int mask = CamWnd_GetFilterMask(cam);
mask ^= bit;
@@ -1211,6 +1283,9 @@ static void CamWnd_HandleMenuCommand(CCamWnd* cam, int command) {
case CAMWND_MENU_CMD_CUBIC_CLIPPING:
CamWnd_ToggleCubicClipping(cam);
break;
case CAMWND_MENU_CMD_DECAL_EDITING:
CamWnd_ToggleDecalEditing(cam);
break;
case CAMWND_MENU_CMD_SHOW_WORLD:
CamWnd_ToggleFilterBit(cam, CAMWND_FILTER_HIDE_WORLD);
break;
@@ -1268,6 +1343,28 @@ static void CamWnd_ShowLightingMenu(HWND hWnd, CCamWnd* cam) {
}
}
static void CamWnd_ShowDecalsMenu(HWND hWnd, CCamWnd* cam) {
RECT itemRect;
POINT pt;
HMENU menu;
int command;
CamWnd_GetMenuItemRect(hWnd, 2, itemRect);
pt.x = itemRect.left;
pt.y = itemRect.bottom;
ClientToScreen(hWnd, &pt);
menu = CreatePopupMenu();
AppendMenu(menu, MF_STRING | (CamWnd_DecalEditingEnabled(cam) ? MF_CHECKED : 0), CAMWND_MENU_CMD_DECAL_EDITING, "Enable decal editing");
command = TrackPopupMenu(menu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, hWnd, NULL);
DestroyMenu(menu);
if (command) {
CamWnd_HandleMenuCommand(cam, command);
}
}
static void CamWnd_ShowFiltersMenu(HWND hWnd, CCamWnd* cam) {
RECT itemRect;
POINT pt;
@@ -1313,6 +1410,9 @@ static void CamWnd_ShowTopMenu(HWND hWnd, int item) {
else if (item == 1) {
CamWnd_ShowFiltersMenu(hWnd, cam);
}
else if (item == 2) {
CamWnd_ShowDecalsMenu(hWnd, cam);
}
}
static void CamWnd_RegisterMenuBarClass() {
@@ -1397,6 +1497,7 @@ static void CamWnd_DestroyMenuBar(CCamWnd* cam) {
RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_REBUILD_MODE);
RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_ENTITY_MODE);
RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_FILTER_MASK);
RemoveProp(cam->GetSafeHwnd(), CAMWND_PROP_DECAL_EDITING);
}
static bool CamWnd_PointInMenuBar(CCamWnd* cam, const CPoint& point) {
@@ -1703,9 +1804,11 @@ static void CamWnd_FaceExtrudeBuildRay(CCamWnd* cam, const CPoint& point, idVec3
float u = 0.0f;
float r = 0.0f;
if (camera.width > 0) {
u = (float)(y - camera.height / 2) / (camera.width / 2);
r = (float)(x - camera.width / 2) / (camera.width / 2);
}
if (camera.width > 0) {
u = (float)(y - camera.height / 2) / (camera.width / 2);
}
for (int i = 0; i < 3; i++) {
dir[i] = camera.vpn[i] + camera.vright[i] * r + camera.vup[i] * u;
@@ -1713,6 +1816,75 @@ static void CamWnd_FaceExtrudeBuildRay(CCamWnd* cam, const CPoint& point, idVec3
dir.Normalize();
}
static bool CamWnd_DecalClick(CCamWnd* cam, const CPoint& point, UINT nFlags) {
if (!CamWnd_DecalEditingEnabled(cam) || cam == NULL) {
return false;
}
idVec3 dir;
CamWnd_FaceExtrudeBuildRay(cam, point, dir);
if (nFlags & MK_SHIFT) {
Map_SelectDecalByRay(cam->Camera().origin, dir);
return true;
}
idVec3 hitPoint;
idVec3 hitNormal;
float hitDist = HUGE_DISTANCE;
bool hitBrush = false;
const char* hitSource = "none";
qertrace_t trace = Test_Ray(cam->Camera().origin, dir, 0);
if (trace.brush != NULL && trace.face != NULL && trace.dist > 0.0f && trace.dist < hitDist) {
hitBrush = true;
hitSource = "brush";
hitDist = trace.dist;
hitPoint = cam->Camera().origin + dir * trace.dist;
hitNormal = trace.face->plane.Normal();
}
if (g_qeglobals.rw) {
modelTrace_t modelTrace;
idVec3 end = cam->Camera().origin + dir * HUGE_DISTANCE;
if (g_qeglobals.rw->Trace(modelTrace, cam->Camera().origin, end, 0.0f, false, false)) {
float modelDist = (modelTrace.point - cam->Camera().origin) * dir;
if (!hitBrush && modelDist > 0.0f && modelDist < hitDist) {
hitSource = "render";
hitDist = modelDist;
hitPoint = modelTrace.point;
hitNormal = modelTrace.normal;
}
}
}
if (hitDist <= 0.0f || hitDist >= HUGE_DISTANCE || hitNormal.LengthSqr() < 0.0001f) {
return true;
}
renderWorldDecal_t decal;
CamWnd_DecalMaterial(decal.material);
CamWnd_DecalColorFromSelectedMaterial(decal.material, decal.color);
decal.origin = hitPoint;
decal.normal = hitNormal;
if ((decal.normal * dir) > 0.0f) {
decal.normal = -decal.normal;
}
decal.axisU = decal.normal.Cross(cam->Camera().vup);
if (decal.axisU.LengthSqr() < 0.0001f) {
decal.axisU = decal.normal.Cross(cam->Camera().vright);
}
decal.axisV = decal.normal.Cross(decal.axisU);
decal.size = CamWnd_DecalFloat("size", "64");
decal.depth = CamWnd_DecalFloat("depth", "8");
decal.opacity = CamWnd_DecalFloat("opacity", "1");
Map_AddDecal(decal);
Sys_Status(va("Placed decal using %s on %s at %.2f %.2f %.2f\n", decal.material.c_str(), hitSource, decal.origin.x, decal.origin.y, decal.origin.z), 0);
Sys_UpdateWindows(W_CAMERA);
return true;
}
static bool CamWnd_FaceExtrudeBrushAllowed(CCamWnd* cam, brush_t* brush) {
if (brush == NULL || brush->owner == NULL || brush->owner->eclass == NULL) {
return false;
@@ -2665,6 +2837,9 @@ static LRESULT CALLBACK CamWnd_MenuBarProc(HWND hWnd, UINT uMsg, WPARAM wParam,
CamWnd_GetMenuItemRect(hWnd, 1, itemRect);
RoundRect(hDC, itemRect.left + 3, itemRect.top + 2, itemRect.right - 3, itemRect.bottom - 2, 6, 6);
DrawText(hDC, "Filters", -1, &itemRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
CamWnd_GetMenuItemRect(hWnd, 2, itemRect);
RoundRect(hDC, itemRect.left + 3, itemRect.top + 2, itemRect.right - 3, itemRect.bottom - 2, 6, 6);
DrawText(hDC, "Decals", -1, &itemRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
::SelectObject(hDC, oldPen);
::SelectObject(hDC, oldBrush);
::DeleteObject(borderPen);
@@ -2849,6 +3024,10 @@ void CCamWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
CamWnd_FaceExtrudeEnd(this, false);
return;
}
if (nChar == VK_DELETE && CamWnd_DecalEditingEnabled(this) && Map_GetSelectedDecal() >= 0) {
Map_DeleteSelectedDecal();
return;
}
if (CameraNav_HandleKeyDown(this, nChar)) {
return;
}
@@ -2975,6 +3154,9 @@ void CCamWnd::OnLButtonDown(UINT nFlags, CPoint point) {
if ((nFlags & MK_CONTROL) && (nFlags & MK_SHIFT) && CamWnd_FaceExtrudeBegin(this, point)) {
return;
}
if (CamWnd_DecalClick(this, point, nFlags)) {
return;
}
if (CamWnd_GizmoBegin(this, point, nFlags)) {
return;
}
@@ -3857,7 +4039,6 @@ static void CamWnd_DrawMoveSelectedBrushSides(const camWndBrushFilterContext_t&
glPopAttrib();
}
extern void glLabeledPoint(idVec4& color, idVec3& point, float size, const char* label);
void DrawAxial(face_t* selFace) {
if (g_bAxialMode) {
@@ -4084,6 +4265,9 @@ void CCamWnd::Cam_Draw() {
}
CamWnd_DrawMoveSelectedBrushSides(brushFilter);
if (!renderMode && g_qeglobals.rw && CamWnd_DecalEditingEnabled(this)) {
g_qeglobals.rw->SubmitWorldDecalsToScreenSpace();
}
CamWnd_FaceExtrudeDrawPreview(this);
CamWnd_GizmoDraw(this);
@@ -4141,7 +4325,7 @@ void CCamWnd::Cam_Draw() {
CameraNav_DrawOverlay(this);
glDisable(GL_SCISSOR_TEST);
glFinish();
//glFinish();
QE_CheckOpenGLForErrors();
if (!renderMode) {
@@ -5682,6 +5866,17 @@ void CCamWnd::Cam_Render() {
}
Cam_SetGlobalFogFromWorldspawn(refdef);
if (g_qeglobals.rw && CamWnd_DecalEditingEnabled(this)) {
for (int i = 0; i < g_qeglobals.rw->NumWorldDecals(); ++i) {
const renderWorldDecal_t* decal = g_qeglobals.rw->GetWorldDecal(i);
if (!decal) {
continue;
}
idVec4 color = (i == Map_GetSelectedDecal()) ? idVec4(1.0f, 0.85f, 0.1f, 1.0f) : idVec4(0.1f, 0.8f, 1.0f, 1.0f);
g_qeglobals.rw->DebugCircle(color, decal->origin, decal->normal, decal->size * 0.5f, 32, 0, false);
}
}
g_qeglobals.rw->RenderScene(&refdef);
int frontEnd, backEnd;
+210
View File
@@ -82,6 +82,209 @@ void Map_SaveBetween(void) {
}
static int s_selectedWorldDecal = -1;
static idStr Map_DecalFileName(const char* filename) {
idStr decalFile = filename ? filename : currentmap;
decalFile.StripFileExtension();
decalFile.SetFileExtension(".stamp");
return decalFile;
}
static void Map_NormalizeDecal(renderWorldDecal_t& decal) {
if (decal.normal.LengthSqr() < 0.0001f) {
decal.normal.Set(0.0f, 0.0f, 1.0f);
}
decal.normal.Normalize();
decal.axisU -= decal.normal * (decal.axisU * decal.normal);
if (decal.axisU.LengthSqr() < 0.0001f) {
decal.axisU = decal.normal.Cross(idVec3(0.0f, 0.0f, 1.0f));
if (decal.axisU.LengthSqr() < 0.0001f) {
decal.axisU = decal.normal.Cross(idVec3(0.0f, 1.0f, 0.0f));
}
}
decal.axisU.Normalize();
decal.axisV = decal.normal.Cross(decal.axisU);
decal.axisV.Normalize();
if (decal.size <= 0.0f) {
decal.size = 64.0f;
}
if (decal.depth <= 0.0f) {
decal.depth = 8.0f;
}
if (decal.opacity <= 0.0f) {
decal.opacity = 1.0f;
}
}
int Map_AddDecal(const renderWorldDecal_t& inDecal) {
if (!g_qeglobals.rw) {
return -1;
}
renderWorldDecal_t decal = inDecal;
Map_NormalizeDecal(decal);
s_selectedWorldDecal = g_qeglobals.rw->AddWorldDecal(decal);
mapModified = 1;
return s_selectedWorldDecal;
}
int Map_GetSelectedDecal(void) {
return s_selectedWorldDecal;
}
void Map_DeleteSelectedDecal(void) {
if (!g_qeglobals.rw || s_selectedWorldDecal < 0) {
return;
}
g_qeglobals.rw->RemoveWorldDecal(s_selectedWorldDecal);
s_selectedWorldDecal = -1;
mapModified = 1;
Sys_UpdateWindows(W_ALL);
}
int Map_SelectDecalByRay(const idVec3& origin, const idVec3& dir) {
if (!g_qeglobals.rw) {
return -1;
}
float bestT = 1e30f;
int bestIndex = -1;
for (int i = 0; i < g_qeglobals.rw->NumWorldDecals(); ++i) {
const renderWorldDecal_t* decal = g_qeglobals.rw->GetWorldDecal(i);
if (!decal) {
continue;
}
float denom = dir * decal->normal;
if (fabs(denom) < 0.0001f) {
continue;
}
float t = ((decal->origin - origin) * decal->normal) / denom;
if (t <= 0.0f || t >= bestT) {
continue;
}
idVec3 hit = origin + dir * t;
idVec3 rel = hit - decal->origin;
float u = rel * decal->axisU;
float v = rel * decal->axisV;
if (fabs(u) <= decal->size * 0.5f && fabs(v) <= decal->size * 0.5f) {
bestT = t;
bestIndex = i;
}
}
s_selectedWorldDecal = bestIndex;
Sys_UpdateWindows(W_CAMERA);
return bestIndex;
}
void Map_SaveDecals(const char* filename) {
if (!g_qeglobals.rw) {
return;
}
idStr decalFile = Map_DecalFileName(filename);
const bool osPath = strstr(decalFile.c_str(), ":") != NULL;
idFile* file = osPath ? fileSystem->OpenExplicitFileWrite(decalFile.c_str()) : fileSystem->OpenFileWrite(decalFile.c_str());
if (!file) {
common->Warning("Map_SaveDecals: couldn't write %s", decalFile.c_str());
return;
}
file->WriteFloatString("worldDecals 1 {\n");
for (int i = 0; i < g_qeglobals.rw->NumWorldDecals(); ++i) {
const renderWorldDecal_t* d = g_qeglobals.rw->GetWorldDecal(i);
if (!d) {
continue;
}
file->WriteFloatString("\tdecal {\n");
file->WriteFloatString("\t\tmaterial \"%s\"\n", d->material.c_str());
file->WriteFloatString("\t\torigin ( %f %f %f )\n", d->origin.x, d->origin.y, d->origin.z);
file->WriteFloatString("\t\tnormal ( %f %f %f )\n", d->normal.x, d->normal.y, d->normal.z);
file->WriteFloatString("\t\taxisU ( %f %f %f )\n", d->axisU.x, d->axisU.y, d->axisU.z);
file->WriteFloatString("\t\taxisV ( %f %f %f )\n", d->axisV.x, d->axisV.y, d->axisV.z);
file->WriteFloatString("\t\tsize %f\n", d->size);
file->WriteFloatString("\t\tdepth %f\n", d->depth);
file->WriteFloatString("\t\topacity %f\n", d->opacity);
file->WriteFloatString("\t\tcolor ( %f %f %f %f )\n", d->color.x, d->color.y, d->color.z, d->color.w);
file->WriteFloatString("\t}\n");
}
file->WriteFloatString("}\n");
fileSystem->CloseFile(file);
}
void Map_LoadDecals(const char* filename) {
if (!g_qeglobals.rw) {
return;
}
g_qeglobals.rw->ClearWorldDecals();
s_selectedWorldDecal = -1;
idStr decalFile = Map_DecalFileName(filename);
const bool osPath = strstr(decalFile.c_str(), ":") != NULL;
idLexer src(LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE | LEXFL_ALLOWPATHNAMES);
src.LoadFile(decalFile.c_str(), osPath);
if (!src.IsLoaded()) {
return;
}
idToken token;
if (!src.ReadToken(&token) || token.Icmp("worldDecals")) {
return;
}
src.ReadToken(&token);
if (token != "{") {
src.ExpectTokenString("{");
}
while (src.ReadToken(&token)) {
if (token == "}") {
break;
}
if (token.Icmp("decal")) {
break;
}
renderWorldDecal_t decal;
decal.material = "textures/decals/default";
decal.origin.Zero();
decal.normal.Set(0.0f, 0.0f, 1.0f);
decal.axisU.Set(1.0f, 0.0f, 0.0f);
decal.axisV.Set(0.0f, 1.0f, 0.0f);
decal.size = 64.0f;
decal.depth = 8.0f;
decal.opacity = 1.0f;
decal.color.Set(0.05f, 0.05f, 0.05f, 1.0f);
src.ExpectTokenString("{");
while (src.ReadToken(&token)) {
if (token == "}") {
break;
}
if (!token.Icmp("material")) {
src.ExpectAnyToken(&token);
decal.material = token;
} else if (!token.Icmp("origin")) {
src.Parse1DMatrix(3, decal.origin.ToFloatPtr());
} else if (!token.Icmp("normal")) {
src.Parse1DMatrix(3, decal.normal.ToFloatPtr());
} else if (!token.Icmp("axisU")) {
src.Parse1DMatrix(3, decal.axisU.ToFloatPtr());
} else if (!token.Icmp("axisV")) {
src.Parse1DMatrix(3, decal.axisV.ToFloatPtr());
} else if (!token.Icmp("size")) {
decal.size = src.ParseFloat();
} else if (!token.Icmp("depth")) {
decal.depth = src.ParseFloat();
} else if (!token.Icmp("opacity")) {
decal.opacity = src.ParseFloat();
} else if (!token.Icmp("color")) {
src.Parse1DMatrix(4, decal.color.ToFloatPtr());
}
}
Map_AddDecal(decal);
}
s_selectedWorldDecal = -1;
mapModified = 0;
}
/*
=======================================================================================================================
=======================================================================================================================
@@ -546,6 +749,7 @@ void Map_LoadFile(const char *filename) {
if (g_pParentWnd->GetCamera()->GetRenderMode()) {
g_pParentWnd->GetCamera()->BuildRendererState();
}
Map_LoadDecals(filename);
Sys_EndWait();
Sys_UpdateWindows(W_ALL);
@@ -790,6 +994,9 @@ bool Map_SaveFile(const char *filename, bool use_region, bool autosave) {
sprintf(status, "Writing file %s.%s...", mapFile.c_str(), mapExt.c_str());
dlg.SetText(status);
map.Write(mapFile, mapExt, !(autosave || localFile));
if (!use_region) {
Map_SaveDecals(filename);
}
mapModified = 0;
if (use_region) {
@@ -821,6 +1028,9 @@ void Map_New(void) {
world_entity->brushes.onext = world_entity->brushes.oprev = &world_entity->brushes;
SetKeyValue(world_entity, "classname", "worldspawn");
world_entity->eclass = Eclass_ForName("worldspawn", true);
if (g_qeglobals.rw) {
g_qeglobals.rw->ClearWorldDecals();
}
g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0;
g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0;
+13
View File
@@ -26,6 +26,11 @@ If you have questions concerning this license or the applicable additional terms
===========================================================================
*/
#ifndef __EDITORMAP_H__
#define __EDITORMAP_H__
#include "../../renderer/RenderWorld.h"
extern char currentmap[1024];
// head/tail of doubly linked lists
@@ -52,6 +57,12 @@ void Map_LoadFile (const char *filename);
bool Map_SaveFile (const char *filename, bool use_region, bool autosave = false);
void Map_New (void);
void Map_BuildBrushData(void);
void Map_LoadDecals(const char *filename);
void Map_SaveDecals(const char *filename);
int Map_AddDecal(const renderWorldDecal_t& decal);
void Map_DeleteSelectedDecal(void);
int Map_SelectDecalByRay(const idVec3& origin, const idVec3& dir);
int Map_GetSelectedDecal(void);
void Map_RegionOff (void);
void Map_RegionXY (void);
@@ -65,3 +76,5 @@ void Map_ImportBuffer (char* buf, bool renameEntities = true);
int Map_GetUniqueEntityID(const char *prefix, const char *eclass);
idMapPrimitive *BrushToMapPrimitive( const brush_t *b, const idVec3 &origin );
#endif