engine/editor/compTest.cc

538 lines
13 KiB
C++
Raw Permalink Normal View History

2024-01-07 04:36:33 +00:00
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/guiControl.h"
#include "console/consoleTypes.h"
#include "Core/fileStream.h"
#include "dgl/dgl.h"
#include "GUI/guiScrollCtrl.h"
#include "terrain/terrData.h"
#include <math.h>
//-----------------------------------------------------------------------------
class CompTest : public GuiScrollContentCtrl
{
private:
typedef GuiControl Parent;
S32 mHeights[65536];
S32 mHeightMin;
S32 mHeightMax;
void calcMinMax();
U16 mTerrainHeights[65536];
U32 mCurrentIndex;
Point2I mHilbertPos;
public:
enum {
UP,
LEFT,
DOWN,
RIGHT
};
DECLARE_CONOBJECT(CompTest);
static S32 smShift;
static S32 smHisto;
static S32 smSaveHiLo;
static void consoleInit();
void onRender(Point2I offset, const RectI & updateRect, GuiControl * firstResponder);
void openFile(StringTableEntry fileName);
void saveFile(StringTableEntry fileName);
void buildRep(StringTableEntry type);
void windowCompress();
TerrainBlock * getTerrainObj();
// hilbert curve stuff
void hilbertFill(S32 level, S32 direction = UP);
void move(S32 direction);
};
S32 CompTest::smShift;
S32 CompTest::smHisto;
S32 CompTest::smSaveHiLo;
IMPLEMENT_CONOBJECT(CompTest);
//-----------------------------------------------------------------------------
static void cCompTestOpenFile(SimObject * obj, S32, const char ** argv)
{
static_cast<CompTest*>(obj)->openFile(argv[2]);
}
static void cCompTestSaveFile(SimObject * obj, S32, const char ** argv)
{
static_cast<CompTest*>(obj)->saveFile(argv[2]);
}
static void cCompTestBuildRep(SimObject * obj, S32, const char ** argv)
{
static_cast<CompTest*>(obj)->buildRep(argv[2]);
}
void CompTest::consoleInit()
{
Con::addCommand("CompTest", "buildRep", cCompTestBuildRep, "compTest.buildRep(type)", 3, 3);
Con::addCommand("CompTest", "openFile", cCompTestOpenFile, "compTest.openFile(filename)", 3, 3);
Con::addCommand("CompTest", "saveFile", cCompTestSaveFile, "compTest.saveFile(filename)", 3, 3);
Con::addVariable("CompTestShift", TypeS32, &smShift);
Con::addVariable("CompTestHisto", TypeS32, &smHisto);
Con::addVariable("CompTestSaveHiLo", TypeS32, &smSaveHiLo);
}
//-----------------------------------------------------------------------------
// BEGIN Hilbert curve stuff
void CompTest::move(S32 direction)
{
switch(direction)
{
case LEFT:
mHilbertPos.x--;
break;
case RIGHT:
mHilbertPos.x++;
break;
case UP:
mHilbertPos.y--;
break;
case DOWN:
mHilbertPos.y++;
break;
}
AssertFatal(mCurrentIndex < 256 * 256, "Doh!");
AssertFatal(mHilbertPos.x + 256 * mHilbertPos.y < 256 * 256, "Blah!");
// copy at the hilbert position
mHeights[mCurrentIndex++] = mTerrainHeights[mHilbertPos.x + 256 * mHilbertPos.y];
}
void CompTest::hilbertFill(S32 level, S32 direction)
{
if (level==1) {
switch (direction) {
case LEFT:
move(RIGHT); /* move() could draw a line in... */
move(DOWN); /* ...the indicated direction */
move(LEFT);
break;
case RIGHT:
move(LEFT);
move(UP);
move(RIGHT);
break;
case UP:
move(DOWN);
move(RIGHT);
move(UP);
break;
case DOWN:
move(UP);
move(LEFT);
move(DOWN);
break;
} /* switch */
} else {
switch (direction) {
case LEFT:
hilbertFill(level-1,UP);
move(RIGHT);
hilbertFill(level-1,LEFT);
move(DOWN);
hilbertFill(level-1,LEFT);
move(LEFT);
hilbertFill(level-1,DOWN);
break;
case RIGHT:
hilbertFill(level-1,DOWN);
move(LEFT);
hilbertFill(level-1,RIGHT);
move(UP);
hilbertFill(level-1,RIGHT);
move(RIGHT);
hilbertFill(level-1,UP);
break;
case UP:
hilbertFill(level-1,LEFT);
move(DOWN);
hilbertFill(level-1,UP);
move(RIGHT);
hilbertFill(level-1,UP);
move(UP);
hilbertFill(level-1,RIGHT);
break;
case DOWN:
hilbertFill(level-1,RIGHT);
move(UP);
hilbertFill(level-1,DOWN);
move(LEFT);
hilbertFill(level-1,DOWN);
move(DOWN);
hilbertFill(level-1,LEFT);
break;
}
}
}
// END Hilbert curve stuff
//------------------------------------------------------------------------------
static S32 QSORT_CALLBACK sortHisto(const void * a, const void * b)
{
S16 intA = *((S16*)a);
S16 intB = *((S16*)b);
return(intA == intB ? 0 : intA > intB ? -1 : 1);
}
//-----------------------------------------------------------------------------
TerrainBlock * CompTest::getTerrainObj()
{
// get the terrain obj
SimObject* obj = Sim::findObject("Terrain");
if(!obj)
return(0);
TerrainBlock * terrain = static_cast<TerrainBlock *>(obj);
return(terrain);
}
//-----------------------------------------------------------------------------
void CompTest::windowCompress()
{
U16 window[32];
S32 size = 32 * 16;
S32 windowCount = 0;
S32 i;
for(i = 0; i < 65536 && windowCount < 32; i++)
{
U16 h = mHeights[i];
S32 j;
for(j = 0; j < windowCount;j++)
if(window[j] == h)
break;
if(j == windowCount)
window[windowCount++] = h;
}
S32 runStart = 0;
S32 runCount = 0;
S32 winPos = 0;
for(i = 0; i < 65536; i++)
{
U16 h = mHeights[i];
S32 j;
for(j = 0; j < windowCount; j++)
if(h == window[j])
break;
if(j == windowCount)
{
size += runCount * 5 + 32;
window[winPos++] = h;
if(winPos == windowCount)
winPos = 0;
runStart = i+1;
runCount = 0;
}
else
runCount++;
}
Con::printf("Compressed size: %d", size >> 3);
}
void CompTest::buildRep(StringTableEntry type)
{
TerrainBlock * terrain = getTerrainObj();
if(!terrain)
return;
U16 *htcpy = terrain->heightMap;
for(S32 y = 0; y < 256; y++)
for(S32 x = 0; x < 256; x++)
mTerrainHeights[y * 256 + x] = htcpy[y * 257 + x];
// check for shift
if(smShift)
for(U32 i = 0; i < 256<<8; i++)
mTerrainHeights[i] >>= smShift;
// just copy
if(!dStricmp(type, "baseline"))
{
for(U32 i = 0; i < 256 * 256; i++)
mHeights[i] = mTerrainHeights[i];
}
// hilbert curve
else if(!dStricmp(type, "hilbert"))
{
mHilbertPos.x = mHilbertPos.y = 0;
mHeights[0] = mTerrainHeights[0];
mCurrentIndex = 1;
hilbertFill(8,UP);
}
// MarkF delta type
else if(!dStricmp(type, "delta"))
{
for(U32 y = 0; y < 256; y++)
for(U32 x = 0; x < 256; x++)
{
U16 h1 = mTerrainHeights[x + (y<<8)];
U16 h2 = mTerrainHeights[((x+1) % 256) + (y << 8)];
U16 h3 = mTerrainHeights[x + (((y+1) % 256) << 8)];
U16 h4 = mTerrainHeights[((x+1) % 256) + (((y+1) % 256) << 8)];
mHeights[x + (y<<8)] = h4 - h1 + (h2 - h1) + (h3 - h1);
}
}
else if(!dStricmp(type, "delta2"))
{
U16 prevHeight = 0;
for(U32 i = 0; i < 65536; i++)
{
mHeights[i] = mTerrainHeights[i] - prevHeight;
prevHeight = mTerrainHeights[i];
}
}
else if(!dStricmp(type, "delta3"))
{
mHeights[0] = mTerrainHeights[0];
S32 delta = mTerrainHeights[0] / 2;
S32 deltaPrev = mTerrainHeights[0] - delta;
for(U32 i = 0; i < 65536; i++)
{
S32 ph = mTerrainHeights[i-1];
S32 h = mTerrainHeights[i];
mHeights[i] = h - ph - ((delta + deltaPrev) >> 1);
deltaPrev = delta;
delta = h - ph;
}
/*for(U32 y = 0; y < 256; y++)
{
U32 prevy = (y - 1) & 0xFF;
U16 *prevRow = mTerrainHeights + prevy * 256;
U16 *curRow = mTerrainHeights + y * 256;
S16 *dest = mHeights + y *256;
for(U32 x = 0; x < 256; x++)
dest[x] = curRow[x] - prevRow[x];
}*/
/* U16 prevDelta = 0;
U16 prevHeight = 0;
for(U32 i = 0; i < 65536; i++)
{
U16 h = mTerrainHeights[i];
mHeights[i] = h - (prevHeight + prevDelta);
prevHeight = h;
prevDelta = mHeights[i];
}
prevHeight = 0;
prevDelta = 0;
for(U32 i = 0; i < 65536; i++)
{
U16 newDelta = mHeights[i];
mHeights[i] = prevHeight + prevDelta + newDelta;
prevDelta = newDelta;
prevHeight = mHeights[i];
}*/
}
else
return;
// check for histo display
windowCompress();
if(smHisto)
{
S16 *hist = new S16[256*256];
U32 i;
for(i = 0; i < 256*256; i++)
hist[i] = 0;
for(i = 0; i < 256*256; i++)
hist[U16(mHeights[i])]++;
dQsort(hist, 256*256, 2, sortHisto);
for(i = 0; i < 256*256; i++)
mHeights[i] = hist[i];
U32 used = 0;
for(i = 0; i < 256*256; i++)
if(mHeights[i])
used++;
delete [] hist;
Con::printf("compTest => number of unique histogram entries: %d", used);
F32 sum = 0;
for(i = 0; i < 65536; i++)
{
if(hist[i] == 0)
continue;
F32 p = hist[i] / 65536.0f;
sum += p * log(p) / log(2.0);
}
Con::printf("Compressability sum: %f", -sum);
}
calcMinMax();
Con::printf("compTest => min/max terrain height: %f / %f",
F32(mHeightMin) * 0.03125, F32(mHeightMax) * 0.03125);
}
//-----------------------------------------------------------------------------
void CompTest::calcMinMax()
{
mHeightMin = 32000;
mHeightMax = -32000;
for(U32 i = 0; i < (256*256); i++)
{
if(mHeights[i] < mHeightMin)
mHeightMin = mHeights[i];
if(mHeights[i] > mHeightMax)
mHeightMax = mHeights[i];
}
}
//-----------------------------------------------------------------------------
void CompTest::openFile(StringTableEntry fileName)
{
if(!fileName || !dStrlen(fileName))
return;
FileStream file;
if(!file.open(fileName, FileStream::Read))
return;
for(U32 i = 0; i < (256*256); i++)
{
if(!file.read(&mHeights[i]))
return;
}
calcMinMax();
}
void CompTest::saveFile(StringTableEntry fileName)
{
if(!fileName || !dStrlen(fileName) || !mHeights)
return;
FileStream file;
file.open(fileName, FileStream::ReadWrite);
U32 i;
for(i = 0; i < (256*256); i++)
file.write(mHeights[i]);
file.close();
if(smSaveHiLo)
{
// save lo data
file.open("lo_byte.out", FileStream::ReadWrite);
for(i = 0; i < (256*256); i++)
{
U8 out = mHeights[i];
file.write(out);
}
// save high data
file.open("hi_byte.out", FileStream::ReadWrite);
for(i = 0; i < (256*256); i++)
{
U8 out = mHeights[i] >> 8;
file.write(out);
}
}
}
//-----------------------------------------------------------------------------
void CompTest::onRender(Point2I offset, const RectI & updateRect, GuiControl * firstResponder)
{
firstResponder;
if(!mHeights)
return;
dglSetViewport(updateRect);
GuiControl * parent = getParent();
if(!parent)
return;
Point2I parentOff = parent->localToGlobalCoord(Point2I(0,0));
offset -= parentOff;
// clear the background only
// glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_QUADS);
glColor3f(0.2, 0.2, 0.2);
glVertex2f(updateRect.point.x, updateRect.point.y);
glVertex2f(updateRect.point.x + updateRect.extent.x, updateRect.point.y);
glVertex2f(updateRect.point.x + updateRect.extent.x, updateRect.point.y + updateRect.extent.y);
glVertex2f(updateRect.point.x, updateRect.point.y + updateRect.extent.y);
glEnd();
// draw forest, draw!
glBegin(GL_LINES);
glColor3f(0.8,0,0);
// check for neg vals
if(mHeightMin < 0)
{
U16 range = mHeightMax > -mHeightMin ? mHeightMax : -mHeightMin;
for(U32 i = 0; i < updateRect.extent.x; i++)
{
U32 index = i + -offset.x;
if(i >= 256 * 256)
break;
S16 curHeight = mHeights[index];
F32 bottom = updateRect.point.y + updateRect.extent.y / 2;
glVertex2f(i, bottom);
F32 scale = F32(curHeight) / F32(range);
F32 top = bottom - F32(updateRect.extent.y / 2) * scale;
glVertex2f(i, top);
}
}
else
{
U16 range = mHeightMax - mHeightMin;
F32 maxScale = 0.f;
for(U32 i = 0; i < updateRect.extent.x; i++)
{
U32 index = i + -offset.x;
if(index >= 256 * 256)
break;
U16 curHeight = mHeights[index];
F32 bottom = updateRect.point.y + updateRect.extent.y;
glVertex2f(updateRect.point.x + i, bottom);
F32 scale = (F32(curHeight) - F32(mHeightMin)) / F32(range);
if(scale > maxScale)
maxScale = scale;
F32 top = bottom - F32(updateRect.extent.y) * scale;
glVertex2f(updateRect.point.x + i, top);
}
}
glEnd();
}