Add option to automatically run the automapper

Also, put automapping config selection seperatelly from the automapper button.
Also, add seed parameter to the automapper.
This commit is contained in:
Bojidar Marinov 2018-10-03 19:16:58 +03:00
parent 61559f2ff0
commit c52a3c970e
6 changed files with 151 additions and 42 deletions

View file

@ -1,4 +1,5 @@
#include <stdio.h> // sscanf #include <stdio.h> // sscanf
#include <inttypes.h>
#include <engine/console.h> #include <engine/console.h>
#include <engine/storage.h> #include <engine/storage.h>
@ -7,6 +8,35 @@
#include "auto_map.h" #include "auto_map.h"
#include "editor.h" #include "editor.h"
// Based on triple32inc from https://github.com/skeeto/hash-prospector/tree/79a6074062a84907df6e45b756134b74e2956760
static uint32_t HashUInt32(uint32_t Num)
{
Num++;
Num ^= Num >> 17;
Num *= 0xed5ad4bbu;
Num ^= Num >> 11;
Num *= 0xac4c1b51u;
Num ^= Num >> 15;
Num *= 0x31848babu;
Num ^= Num >> 14;
return Num;
}
#define HASH_MAX 65536
static int HashLocation(uint32_t Seed, uint32_t Run, uint32_t Rule, uint32_t X, uint32_t Y)
{
const uint32_t Prime = 31;
uint32_t Hash = 1;
Hash = Hash * Prime + HashUInt32(Seed);
Hash = Hash * Prime + HashUInt32(Run);
Hash = Hash * Prime + HashUInt32(Rule);
Hash = Hash * Prime + HashUInt32(X);
Hash = Hash * Prime + HashUInt32(Y);
Hash = HashUInt32(Hash * Prime); // Just to double-check that values are well-distributed
return Hash % HASH_MAX;
}
CAutoMapper::CAutoMapper(CEditor *pEditor) CAutoMapper::CAutoMapper(CEditor *pEditor)
{ {
m_pEditor = pEditor; m_pEditor = pEditor;
@ -313,11 +343,14 @@ const char* CAutoMapper::GetConfigName(int Index)
return m_lConfigs[Index].m_aName; return m_lConfigs[Index].m_aName;
} }
void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID) void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID, int Seed)
{ {
if(!m_FileLoaded || pLayer->m_Readonly || ConfigID < 0 || ConfigID >= m_lConfigs.size()) if(!m_FileLoaded || pLayer->m_Readonly || ConfigID < 0 || ConfigID >= m_lConfigs.size())
return; return;
if(Seed == 0)
Seed = rand();
CConfiguration *pConf = &m_lConfigs[ConfigID]; CConfiguration *pConf = &m_lConfigs[ConfigID];
// for every run: copy tiles, automap, overwrite tiles // for every run: copy tiles, automap, overwrite tiles
@ -405,7 +438,7 @@ void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID)
} }
if(RespectRules && if(RespectRules &&
(pIndexRule->m_RandomProbability >= 1.0 || (float)rand() / ((float)RAND_MAX + 1) < pIndexRule->m_RandomProbability)) (pIndexRule->m_RandomProbability >= 1.0 || HashLocation(Seed, h, i, x, y) < HASH_MAX * pIndexRule->m_RandomProbability))
{ {
pTile->m_Index = pIndexRule->m_ID; pTile->m_Index = pIndexRule->m_ID;
pTile->m_Flags = pIndexRule->m_Flag; pTile->m_Flags = pIndexRule->m_Flag;

View file

@ -54,7 +54,7 @@ public:
CAutoMapper(class CEditor *pEditor); CAutoMapper(class CEditor *pEditor);
void Load(const char* pTileName); void Load(const char* pTileName);
void Proceed(class CLayerTiles *pLayer, int ConfigID); void Proceed(class CLayerTiles *pLayer, int ConfigID, int Seed=0);
int ConfigNamesNum() const { return m_lConfigs.size(); } int ConfigNamesNum() const { return m_lConfigs.size(); }
const char* GetConfigName(int Index); const char* GetConfigName(int Index);

View file

@ -3163,6 +3163,24 @@ int CEditor::DoProperties(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int *
Change = i; Change = i;
} }
} }
else if(pProps[i].m_Type == PROPTYPE_AUTOMAPPER)
{
char aBuf[64];
if(pProps[i].m_Value < 0 || pProps[i].m_Min < 0 || pProps[i].m_Min >= m_Map.m_lImages.size())
str_copy(aBuf, "None", sizeof(aBuf));
else
str_format(aBuf, sizeof(aBuf),"%s", m_Map.m_lImages[pProps[i].m_Min]->m_AutoMapper.GetConfigName(pProps[i].m_Value));
if(DoButton_Editor(&pIDs[i], aBuf, 0, &Shifter, 0, 0))
PopupSelectConfigAutoMapInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY());
int r = PopupSelectConfigAutoMapResult();
if(r >= -1)
{
*pNewVal = r;
Change = i;
}
}
} }
return Change; return Change;
@ -3346,7 +3364,7 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect View)
} }
static int s_LayerPopupID = 0; static int s_LayerPopupID = 0;
if(Result == 2) if(Result == 2)
UiInvokePopupMenu(&s_LayerPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 280, PopupLayer); UiInvokePopupMenu(&s_LayerPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 300, PopupLayer);
} }
LayerCur += 14.0f; LayerCur += 14.0f;

View file

@ -505,6 +505,7 @@ enum
PROPTYPE_ENVELOPE, PROPTYPE_ENVELOPE,
PROPTYPE_SHIFT, PROPTYPE_SHIFT,
PROPTYPE_SOUND, PROPTYPE_SOUND,
PROPTYPE_AUTOMAPPER,
}; };
typedef struct typedef struct
@ -552,6 +553,8 @@ public:
void GetSize(float *w, float *h) { *w = m_Width*32.0f; *h = m_Height*32.0f; } void GetSize(float *w, float *h) { *w = m_Width*32.0f; *h = m_Height*32.0f; }
void TryInvokeAutomapper();
int m_TexID; int m_TexID;
int m_Game; int m_Game;
int m_Image; int m_Image;
@ -564,6 +567,9 @@ public:
// DDRace // DDRace
int m_AutoMapperConfig;
int m_Seed;
bool m_AutoAutoMap;
int m_Tele; int m_Tele;
int m_Speedup; int m_Speedup;
int m_Front; int m_Front;
@ -991,7 +997,7 @@ public:
void PopupSelectGametileOpInvoke(float x, float y); void PopupSelectGametileOpInvoke(float x, float y);
int PopupSelectGameTileOpResult(); int PopupSelectGameTileOpResult();
void PopupSelectConfigAutoMapInvoke(float x, float y); void PopupSelectConfigAutoMapInvoke(int Current, float x, float y);
int PopupSelectConfigAutoMapResult(); int PopupSelectConfigAutoMapResult();
void PopupSelectSoundInvoke(int Current, float x, float y); void PopupSelectSoundInvoke(int Current, float x, float y);

View file

@ -36,6 +36,9 @@ CLayerTiles::CLayerTiles(int w, int h)
m_Front = 0; m_Front = 0;
m_Switch = 0; m_Switch = 0;
m_Tune = 0; m_Tune = 0;
m_AutoMapperConfig = -1;
m_Seed = 0;
m_AutoAutoMap = false;
m_pTiles = new CTile[m_Width*m_Height]; m_pTiles = new CTile[m_Width*m_Height];
mem_zero(m_pTiles, m_Width*m_Height*sizeof(CTile)); mem_zero(m_pTiles, m_Width*m_Height*sizeof(CTile));
@ -395,6 +398,7 @@ void CLayerTiles::FillSelection(bool Empty, CLayer *pBrush, CUIRect Rect)
} }
} }
m_pEditor->m_Map.m_Modified = true; m_pEditor->m_Map.m_Modified = true;
TryInvokeAutomapper();
} }
void CLayerTiles::BrushDraw(CLayer *pBrush, float wx, float wy) void CLayerTiles::BrushDraw(CLayer *pBrush, float wx, float wy)
@ -418,6 +422,7 @@ void CLayerTiles::BrushDraw(CLayer *pBrush, float wx, float wy)
SetTile(fx, fy, l->m_pTiles[y*l->m_Width+x]); SetTile(fx, fy, l->m_pTiles[y*l->m_Width+x]);
} }
m_pEditor->m_Map.m_Modified = true; m_pEditor->m_Map.m_Modified = true;
TryInvokeAutomapper();
} }
void CLayerTiles::BrushFlipX() void CLayerTiles::BrushFlipX()
@ -608,29 +613,11 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox)
CUIRect Button; CUIRect Button;
bool InGameGroup = !find_linear(m_pEditor->m_Map.m_pGameGroup->m_lLayers.all(), this).empty(); bool InGameGroup = !find_linear(m_pEditor->m_Map.m_pGameGroup->m_lLayers.all(), this).empty();
if(m_pEditor->m_Map.m_pGameLayer != this) if(m_pEditor->m_Map.m_pGameLayer == this || m_pEditor->m_Map.m_pTeleLayer == this || m_pEditor->m_Map.m_pSpeedupLayer == this || m_pEditor->m_Map.m_pFrontLayer == this || m_pEditor->m_Map.m_pSwitchLayer == this || m_pEditor->m_Map.m_pTuneLayer == this)
{
if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size() && m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.IsLoaded())
{
static int s_AutoMapperButton = 0;
pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
if(m_pEditor->DoButton_Editor(&s_AutoMapperButton, "Auto map", 0, &Button, 0, ""))
m_pEditor->PopupSelectConfigAutoMapInvoke(m_pEditor->UI()->MouseX(), m_pEditor->UI()->MouseY());
int Result = m_pEditor->PopupSelectConfigAutoMapResult();
if(Result > -1)
{
m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.Proceed(this, Result);
return 1;
}
}
}
else if(m_pEditor->m_Map.m_pGameLayer == this || m_pEditor->m_Map.m_pTeleLayer == this || m_pEditor->m_Map.m_pSpeedupLayer == this || m_pEditor->m_Map.m_pFrontLayer == this || m_pEditor->m_Map.m_pSwitchLayer == this || m_pEditor->m_Map.m_pTuneLayer == this)
InGameGroup = false; InGameGroup = false;
if(InGameGroup) if(InGameGroup)
{ {
pToolBox->HSplitBottom(2.0f, pToolBox, 0);
pToolBox->HSplitBottom(12.0f, pToolBox, &Button); pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
static int s_ColclButton = 0; static int s_ColclButton = 0;
if(m_pEditor->DoButton_Editor(&s_ColclButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer")) if(m_pEditor->DoButton_Editor(&s_ColclButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer"))
@ -697,6 +684,33 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox)
} }
} }
if(m_pEditor->m_Map.m_pGameLayer != this)
{
if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size() && m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.IsLoaded() &&
m_AutoMapperConfig != -1)
{
static int s_AutoMapperButton = 0;
static int s_AutoMapperButtonAuto = 0;
pToolBox->HSplitBottom(2.0f, pToolBox, 0);
pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
if(m_Seed != 0) {
CUIRect ButtonAuto;
Button.VSplitRight(16.0f, &Button, &ButtonAuto);
Button.VSplitRight(2.0f, &Button, 0);
if(m_pEditor->DoButton_Editor(&s_AutoMapperButtonAuto, "A", m_AutoAutoMap, &ButtonAuto, 0, "Automatically run automap after modifications."))
{
m_AutoAutoMap = !m_AutoAutoMap;
TryInvokeAutomapper();
}
}
if(m_pEditor->DoButton_Editor(&s_AutoMapperButton, "Automap", 0, &Button, 0, "Run the automapper"))
{
m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.Proceed(this, m_AutoMapperConfig, m_Seed);
return 1;
}
}
}
enum enum
{ {
PROP_WIDTH=0, PROP_WIDTH=0,
@ -707,6 +721,8 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox)
PROP_COLOR, PROP_COLOR,
PROP_COLOR_ENV, PROP_COLOR_ENV,
PROP_COLOR_ENV_OFFSET, PROP_COLOR_ENV_OFFSET,
PROP_AUTOMAPPER,
PROP_SEED,
NUM_PROPS, NUM_PROPS,
}; };
@ -725,20 +741,26 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox)
{"Color", Color, PROPTYPE_COLOR, 0, 0}, {"Color", Color, PROPTYPE_COLOR, 0, 0},
{"Color Env", m_ColorEnv+1, PROPTYPE_INT_STEP, 0, m_pEditor->m_Map.m_lEnvelopes.size()+1}, {"Color Env", m_ColorEnv+1, PROPTYPE_INT_STEP, 0, m_pEditor->m_Map.m_lEnvelopes.size()+1},
{"Color TO", m_ColorEnvOffset, PROPTYPE_INT_SCROLL, -1000000, 1000000}, {"Color TO", m_ColorEnvOffset, PROPTYPE_INT_SCROLL, -1000000, 1000000},
{"Auto Rule", m_AutoMapperConfig, PROPTYPE_AUTOMAPPER, m_Image, 0},
{"Seed", m_Seed, PROPTYPE_INT_SCROLL, 0, 1000000000},
{0}, {0},
}; };
if(m_pEditor->m_Map.m_pGameLayer == this || m_pEditor->m_Map.m_pTeleLayer == this || m_pEditor->m_Map.m_pSpeedupLayer == this || m_pEditor->m_Map.m_pFrontLayer == this || m_pEditor->m_Map.m_pSwitchLayer == this || m_pEditor->m_Map.m_pTuneLayer == this) // remove the image and color properties if this is the game/tele/speedup/front/switch layer if(m_pEditor->m_Map.m_pGameLayer == this || m_pEditor->m_Map.m_pTeleLayer == this || m_pEditor->m_Map.m_pSpeedupLayer == this || m_pEditor->m_Map.m_pFrontLayer == this || m_pEditor->m_Map.m_pSwitchLayer == this || m_pEditor->m_Map.m_pTuneLayer == this) // remove the image and color properties if this is the game/tele/speedup/front/switch layer
{ {
aProps[4].m_pName = 0; aProps[PROP_IMAGE].m_pName = 0;
aProps[5].m_pName = 0; aProps[PROP_COLOR].m_pName = 0;
aProps[PROP_AUTOMAPPER].m_pName = 0;
}
if(m_Image == -1)
{
aProps[PROP_AUTOMAPPER].m_pName = 0;
aProps[PROP_SEED].m_pName = 0;
} }
static int s_aIds[NUM_PROPS] = {0}; static int s_aIds[NUM_PROPS] = {0};
int NewVal = 0; int NewVal = 0;
int Prop = m_pEditor->DoProperties(pToolBox, aProps, s_aIds, &NewVal); int Prop = m_pEditor->DoProperties(pToolBox, aProps, s_aIds, &NewVal);
if(Prop != -1)
m_pEditor->m_Map.m_Modified = true;
if(Prop == PROP_WIDTH && NewVal > 1) if(Prop == PROP_WIDTH && NewVal > 1)
{ {
@ -772,7 +794,10 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox)
m_Image = -1; m_Image = -1;
} }
else else
{
m_Image = NewVal%m_pEditor->m_Map.m_lImages.size(); m_Image = NewVal%m_pEditor->m_Map.m_lImages.size();
m_AutoMapperConfig = -1;
}
} }
else if(Prop == PROP_COLOR) else if(Prop == PROP_COLOR)
{ {
@ -797,10 +822,32 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox)
} }
if(Prop == PROP_COLOR_ENV_OFFSET) if(Prop == PROP_COLOR_ENV_OFFSET)
m_ColorEnvOffset = NewVal; m_ColorEnvOffset = NewVal;
else if(Prop == PROP_SEED)
{
m_Seed = NewVal;
}
else if(Prop == PROP_AUTOMAPPER)
{
if (m_Image >= 0)
m_AutoMapperConfig = NewVal%m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.ConfigNamesNum();
else
m_AutoMapperConfig = -1;
}
if(Prop != -1) {
m_pEditor->m_Map.m_Modified = true;
TryInvokeAutomapper();
}
return 0; return 0;
} }
void CLayerTiles::TryInvokeAutomapper() {
if (m_Seed != 0 && m_AutoMapperConfig != -1 && m_AutoAutoMap) {
m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.Proceed(this, m_AutoMapperConfig, m_Seed);
m_pEditor->m_Map.m_Modified = true;
}
}
void CLayerTiles::ModifyImageIndex(INDEX_MODIFY_FUNC Func) void CLayerTiles::ModifyImageIndex(INDEX_MODIFY_FUNC Func)
{ {
@ -949,6 +996,7 @@ void CLayerTele::BrushDraw(CLayer *pBrush, float wx, float wy)
} }
} }
m_pEditor->m_Map.m_Modified = true; m_pEditor->m_Map.m_Modified = true;
TryInvokeAutomapper();
} }
void CLayerTele::BrushFlipX() void CLayerTele::BrushFlipX()
@ -1216,6 +1264,7 @@ void CLayerSpeedup::BrushDraw(CLayer *pBrush, float wx, float wy)
} }
} }
m_pEditor->m_Map.m_Modified = true; m_pEditor->m_Map.m_Modified = true;
TryInvokeAutomapper();
} }
void CLayerSpeedup::BrushFlipX() void CLayerSpeedup::BrushFlipX()
@ -1404,6 +1453,7 @@ void CLayerFront::BrushDraw(CLayer *pBrush, float wx, float wy)
SetTile(fx, fy, l->m_pTiles[y*l->m_Width+x]); SetTile(fx, fy, l->m_pTiles[y*l->m_Width+x]);
} }
m_pEditor->m_Map.m_Modified = true; m_pEditor->m_Map.m_Modified = true;
TryInvokeAutomapper();
} }
CLayerSwitch::CLayerSwitch(int w, int h) CLayerSwitch::CLayerSwitch(int w, int h)
@ -1557,6 +1607,7 @@ void CLayerSwitch::BrushDraw(CLayer *pBrush, float wx, float wy)
} }
} }
m_pEditor->m_Map.m_Modified = true; m_pEditor->m_Map.m_Modified = true;
TryInvokeAutomapper();
} }
void CLayerSwitch::FillSelection(bool Empty, CLayer *pBrush, CUIRect Rect) void CLayerSwitch::FillSelection(bool Empty, CLayer *pBrush, CUIRect Rect)
@ -1756,7 +1807,8 @@ void CLayerTune::BrushDraw(CLayer *pBrush, float wx, float wy)
m_pTiles[fy*m_Width+fx].m_Index = 0; m_pTiles[fy*m_Width+fx].m_Index = 0;
} }
} }
m_pEditor->m_Map.m_Modified = true; m_pEditor->m_Map.m_Modified = true;
TryInvokeAutomapper();
} }

View file

@ -1353,6 +1353,7 @@ int CEditor::PopupSelectGameTileOpResult()
} }
static int s_AutoMapConfigSelected = -1; static int s_AutoMapConfigSelected = -1;
static int s_AutoMapConfigCurrent = -1;
int CEditor::PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View) int CEditor::PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View)
{ {
@ -1361,35 +1362,34 @@ int CEditor::PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View)
static int s_AutoMapperConfigButtons[256]; static int s_AutoMapperConfigButtons[256];
CAutoMapper *pAutoMapper = &pEditor->m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper; CAutoMapper *pAutoMapper = &pEditor->m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper;
for(int i = 0; i < pAutoMapper->ConfigNamesNum(); ++i) for(int i = -1; i < pAutoMapper->ConfigNamesNum(); ++i)
{ {
View.HSplitTop(2.0f, 0, &View); View.HSplitTop(2.0f, 0, &View);
View.HSplitTop(12.0f, &Button, &View); View.HSplitTop(12.0f, &Button, &View);
if(pEditor->DoButton_Editor(&s_AutoMapperConfigButtons[i], pAutoMapper->GetConfigName(i), 0, &Button, 0, 0)) if(pEditor->DoButton_MenuItem(&s_AutoMapperConfigButtons[i], i == -1 ? "None" : pAutoMapper->GetConfigName(i), i == s_AutoMapConfigCurrent, &Button, 0, 0))
s_AutoMapConfigSelected = i; s_AutoMapConfigSelected = i;
} }
return 0; return 0;
} }
void CEditor::PopupSelectConfigAutoMapInvoke(float x, float y) void CEditor::PopupSelectConfigAutoMapInvoke(int Current, float x, float y)
{ {
static int s_AutoMapConfigSelectID = 0; static int s_AutoMapConfigSelectID = 0;
s_AutoMapConfigSelected = -1; s_AutoMapConfigSelected = -100;
s_AutoMapConfigCurrent = Current;
CLayerTiles *pLayer = static_cast<CLayerTiles*>(GetSelectedLayer(0)); CLayerTiles *pLayer = static_cast<CLayerTiles*>(GetSelectedLayer(0));
if(pLayer && pLayer->m_Image >= 0 && pLayer->m_Image < m_Map.m_lImages.size() && UiInvokePopupMenu(&s_AutoMapConfigSelectID, 0, x, y, 120.0f, 26.0f+14.0f*m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper.ConfigNamesNum(), PopupSelectConfigAutoMap);
m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper.ConfigNamesNum())
UiInvokePopupMenu(&s_AutoMapConfigSelectID, 0, x, y, 120.0f, 12.0f+14.0f*m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper.ConfigNamesNum(), PopupSelectConfigAutoMap);
} }
int CEditor::PopupSelectConfigAutoMapResult() int CEditor::PopupSelectConfigAutoMapResult()
{ {
if(s_AutoMapConfigSelected < 0) if(s_AutoMapConfigSelected == -100)
return -1; return -100;
int Result = s_AutoMapConfigSelected; s_AutoMapConfigCurrent = s_AutoMapConfigSelected;
s_AutoMapConfigSelected = -1; s_AutoMapConfigSelected = -100;
return Result; return s_AutoMapConfigCurrent;
} }
// DDRace // DDRace