Skip to content

Instantly share code, notes, and snippets.

@jerstlouis
Last active November 1, 2022 17:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jerstlouis/ac061ac064acbbc1e7ec752acf83ce91 to your computer and use it in GitHub Desktop.
Save jerstlouis/ac061ac064acbbc1e7ec752acf83ce91 to your computer and use it in GitHub Desktop.
public import "ecere"
public class CubeTris : Object
{
public:
bool Create(const DisplaySystem displaySystem)
{
bool result = false;
if(this)
{
InitializeMesh(displaySystem);
if(mesh)
{
if(mesh.Allocate({ vertices = true, texCoords1 = true }, 24, displaySystem))
{
Vector3Df vertices[24] =
{
{ -(float)size.x/2,-(float)size.y/2,-(float)size.z/2 },
{ (float)size.x/2,-(float)size.y/2,-(float)size.z/2 },
{ (float)size.x/2, (float)size.y/2,-(float)size.z/2 },
{ -(float)size.x/2, (float)size.y/2,-(float)size.z/2 },
{ -(float)size.x/2,-(float)size.y/2, (float)size.z/2 },
{ (float)size.x/2,-(float)size.y/2, (float)size.z/2 },
{ (float)size.x/2, (float)size.y/2, (float)size.z/2 },
{ -(float)size.x/2, (float)size.y/2, (float)size.z/2 },
{ -(float)size.x/2,-(float)size.y/2,-(float)size.z/2 },
{ (float)size.x/2,-(float)size.y/2,-(float)size.z/2 },
{ (float)size.x/2, (float)size.y/2,-(float)size.z/2 },
{ -(float)size.x/2, (float)size.y/2,-(float)size.z/2 },
{ -(float)size.x/2,-(float)size.y/2, (float)size.z/2 },
{ (float)size.x/2,-(float)size.y/2, (float)size.z/2 },
{ (float)size.x/2, (float)size.y/2, (float)size.z/2 },
{ -(float)size.x/2, (float)size.y/2, (float)size.z/2 },
{ -(float)size.x/2,-(float)size.y/2,-(float)size.z/2 },
{ (float)size.x/2,-(float)size.y/2,-(float)size.z/2 },
{ (float)size.x/2, (float)size.y/2,-(float)size.z/2 },
{ -(float)size.x/2, (float)size.y/2,-(float)size.z/2 },
{ -(float)size.x/2,-(float)size.y/2, (float)size.z/2 },
{ (float)size.x/2,-(float)size.y/2, (float)size.z/2 },
{ (float)size.x/2, (float)size.y/2, (float)size.z/2 },
{ -(float)size.x/2, (float)size.y/2, (float)size.z/2 }
};
Pointf texCoords[24] =
{
{ 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 },
{ 1, 0 }, { 0, 0 }, { 0, 1 }, { 1, 1 },
{ 1, 0 }, { 0, 0 }, { 0, 1 }, { 1, 1 },
{ 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 },
{ 0, 1 }, { 1, 1 }, { 1, 1 }, { 0, 1 },
{ 0, 0 }, { 1, 0 }, { 1, 0 }, { 0, 0 }
};
uint16 indices[36] =
{
// up, front, down, back, right, left
17,21,20, 17,20,16,
0,3,2, 0,2,1,
22,18,19, 22,19,23,
5,6,7, 5,7,4,
9,10,14, 9,14,13,
12,15,11, 12,11,8
};
int c;
PrimitiveGroup group;
CopyBytes(mesh.vertices, vertices, sizeof(vertices));
CopyBytes(mesh.texCoords, texCoords, sizeof(texCoords));
group = mesh.AddPrimitiveGroup(triangles, 36);
if(group)
{
memcpy(group.indices, indices, sizeof(indices));
mesh.UnlockPrimitiveGroup(group);
}
flags.computeLightVectors = true;
mesh.ComputeNormals();
result = true;
mesh.Unlock(0);
}
SetMinMaxRadius(true);
}
}
return result;
}
property Vector3Df size { set { size = value; } };
private:
CubeTris()
{
size = { 1,1,1 };
}
Vector3Df size;
}
import "ecere"
import "mandelbulb"
import "cubeTris"
import "ButterburShader"
import "threadedProcessing"
#include "gl123es.h"
GLMultiDraw mdWorld { };
GLArrayTexture atTextures { };
define CUBES_X = 64; //128;
define CUBES_Y = 64; //128;
define CUBES_Z = 64; //128;
define CUBES_COUNT = CUBES_X * CUBES_Y * CUBES_Z;
//define fogDensity = 0.00018f;
define fogDensity = 0.000085f; // with: float fog = clamp(exp(-fogZ * fogZ), 0.0, 1.0); in butterbur.frag:431
Color fogColor = skyBlue;
define viewDistance = 5;
define numTextures = 9; //512;
define maxLoadedChunks = (uint)((1LL<<31) / (12 * CUBES_COUNT)); // 512;
CubeChunk loadedChunks[maxLoadedChunks];
FreeSpots freeChunks { };
CubicWorld cubicWorld { };
bool freeze;
class LoadTask : ProcessingTask
{
CubeChunk * chunk;
void OnFree()
{
}
}
class LoadingThread : ThreadedProcessing
{
ProcessingAction onPerformTask(ProcessingTask t)
{
LoadTask task = (LoadTask)t;
task.chunk->load();
return clear;
}
void onTaskCleared(ProcessingTask t)
{
LoadTask task = (LoadTask)t;
task.OnFree();
}
}
LoadingThread loadingThread { };
Mutex randomMutex { };
struct CubeChunk
{
int64 ox, oy, oz;
int index; // index into loading buffers
bool loaded;
bool uploaded;
float * transforms;
uint * materials;
uint count;
bool visible;
void free()
{
delete transforms;
delete materials;
}
bool load()
{
Mandelbulb mandelbulb { };
int x, y, z;
float * tr;
uint * mat;
int i, j;
int e;
uint seed = (uint)(oz * 1024 * 1024 + oy * 1024 + ox);
int sx, sy, sz;
int dx, dy, dz;
randomMutex.Wait();
RandomSeed(seed);
mandelbulb.power = GetRandom(0, 9);
mandelbulb.size.x = sx = GetRandom(100, 120) * CUBES_X / 100;
mandelbulb.size.y = sy = GetRandom(100, 120) * CUBES_Y / 100;
mandelbulb.size.z = sz = GetRandom(100, 120) * CUBES_Z / 100;
dx = GetRandom(-sx/4, sx/4);
dy = GetRandom(-sy/4, sy/4);
dz = GetRandom(-sz/4, sz/4);
e = GetRandom(0, 8);
randomMutex.Release();
tr = transforms = new float[CUBES_COUNT * 3];
mat = materials = new uint[CUBES_COUNT];
j = 0;
for(z = 0; z < CUBES_Z; z++)
for(y = 0; y < CUBES_Y; y++)
for(x = 0; x < CUBES_X; x++)
{
Vector3Df p
{
0.5f - CUBES_X/2 + x + dx,
0.5f - CUBES_Y/2 + y + dy,
0.5f - CUBES_Z/2 + z + dz
};
uint t = mandelbulb.isPointInside(p, 6);
if(t)
{
Vector3Df cp { 0.5f - CUBES_X/2 + x, 0.5f - CUBES_Y/2 + y, 0.5f - CUBES_Z/2 + z };
// Transform is relative to center of chunk
tr[3 * j + 0] = (float)cp.x;
tr[3 * j + 1] = (float)cp.y;
tr[3 * j + 2] = (float)cp.z;
mat[j] = (t - 1 + e) % 9;
j++;
}
}
count = j;
transforms = renew transforms float[count * 3];
materials = renew materials uint[count];
loaded = true;
return true;
}
void unload()
{
if(loaded)
{
loaded = false;
freeChunks.markFree(index);
index = -1;
free();
}
}
CubeChunk * ::ensure(int64 ox, int64 oy, int64 oz, bool visible)
{
CubeChunk * result = null;
int ix = -1;
int i;
for(i = 0; i < maxLoadedChunks; i++)
{
CubeChunk * chunk = &loadedChunks[i];
if(chunk->index != -1 && chunk->ox == ox && chunk->oy == oy && chunk->oz == oz)
{
result = chunk;
break;
}
}
if(!result && (ix = freeChunks.next()) != -1)
{
CubeChunk * chunk = &loadedChunks[ix];
chunk->index = ix;
chunk->ox = ox;
chunk->oy = oy;
chunk->oz = oz;
loadingThread.addTask(LoadTask { chunk = chunk }, 1, visible ? 0 : MAXINT);
result = chunk;
}
if(result)
result->visible = visible;
return result;
}
void prepareMultiDraw()
{
int vertNCoords = 3, verticesStride = 32;
uint i, j;
const uint maxLoadedCubes = maxLoadedChunks * CUBES_COUNT;
uint chunkOffset = index * CUBES_COUNT;
if(!uploaded)
{
// mdWorld.transforms = transforms.array;
if(!mdWorld.transformsAB.buffer)
mdWorld.transformsAB.allocate(maxLoadedCubes * 3 * sizeof(float), null, staticDraw);
mdWorld.transformsAB.upload(chunkOffset * 3 * sizeof(float), count * sizeof(float) * 3, transforms);
if(!mdWorld.idsAlloced)
mdWorld.resizeIDs(maxLoadedCubes);
j = chunkOffset;
for(i = 0; i < count; i++)
mdWorld.drawIDs[j++] = materials[i]; // TOCHECK: Do we need this for non-MDEI fallbacks?
mdWorld.idsAB.upload(chunkOffset * sizeof(uint), count * sizeof(uint), materials);
if(!mdWorld.commandsAlloced)
mdWorld.resizeCommands(maxLoadedChunks);
delete transforms;
delete materials;
uploaded = true;
}
mdWorld.commands[mdWorld.commandsCount] =
{
count = 36,
instanceCount = count,
firstIndex = 0,
baseVertex = 0,
baseInstance = chunkOffset
};
mdWorld.commandsCount++;
#if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3)
if(glCaps_vao) glBindVertexArray(mdWorld.vao);
#endif
// TOCHECK: No attrib divisor support in ES 2 -- will it be needed?
#if !defined(CLIENT_MEM_COMMANDS) && ((!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3))
mdWorld.commandsB.upload(0, mdWorld.commandsCount * sizeof(GLDrawCommand), mdWorld.commands);
#endif
// Initial transform buffer setup
if(!glCaps_vao || mdWorld.lastTransformAB != mdWorld.transformsAB.buffer)
{
GLABBindBuffer(GL_ARRAY_BUFFER, mdWorld.transformsAB.buffer);
if(mdWorld.transformSize == 3)
{
glVertexAttribPointer(posOffsetAttribute, mdWorld.transformSize, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribDivisor(posOffsetAttribute, 1);
glEnableVertexAttribArray(posOffsetAttribute);
}
mdWorld.lastTransformAB = mdWorld.transformsAB.buffer;
}
// Initial textureID buffer setup
#if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3)
if(glCaps_shaders && (!glCaps_vao || mdWorld.lastIDAB != mdWorld.idsAB.buffer))
{
GLABBindBuffer(GL_ARRAY_BUFFER, mdWorld.idsAB.buffer);
glVertexAttribIPointer(drawIDAttribute, 1, GL_UNSIGNED_INT, sizeof(uint), 0);
glVertexAttribDivisor(drawIDAttribute, 1);
glEnableVertexAttribArray(drawIDAttribute);
mdWorld.lastIDAB = mdWorld.idsAB.buffer;
}
#endif
if(glCaps_shaders && (!glCaps_vao || mdWorld.lastVBO != mdWorld.vertexGLMB.ab.buffer))
{
if(vertNCoords)
{
GLAB ab { mdWorld.vertexGLMB.ab.buffer };
glEnableVertexAttribArray(GLBufferContents::vertex);
ab.use(vertex, vertNCoords, GL_FLOAT, verticesStride, none, null);
glEnableVertexAttribArray(GLBufferContents::normal);
ab.use(normal, vertNCoords, GL_FLOAT, 32, none, (void *)(uintptr)12);
glEnableVertexAttribArray(GLBufferContents::texCoord);
ab.use(texCoord, 2, GL_FLOAT, 32, none, (void *)(uintptr)24);
mdWorld.vertexStride = verticesStride;
}
mdWorld.lastVBO = mdWorld.vertexGLMB.ab.buffer;
}
if(glCaps_vertexBuffer && (!glCaps_vao || mdWorld.lastIBO != mdWorld.indexGLMB.ab.buffer))
{
GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mdWorld.indexGLMB.ab.buffer);
mdWorld.lastIBO = mdWorld.indexGLMB.ab.buffer;
}
}
void draw(Vector3D cPos)
{
Vector3D chunkPos { ox * CUBES_X, oy * CUBES_Y, oz * CUBES_Z };
mdWorld.commandsCount = 0;
prepareMultiDraw();
glmsPushMatrix();
glmsTranslated(chunkPos.x - cPos.x, chunkPos.y - cPos.y, chunkPos.z - cPos.z);
GLFlushMatrices();
mdWorld.draw();
glmsPopMatrix();
}
};
struct FPS
{
uint frameCount0, frameCount;
double frameTime0;
float fps;
void Start()
{
frameCount0 = frameCount = 0;
fps = 0;
frameTime0 = GetTime();
}
void Step()
{
double frameTime;
double elapsedTime;
frameCount++;
frameTime = GetTime();
elapsedTime = frameTime-frameTime0;
if (elapsedTime > 1)
{
fps = (float)((double)(frameCount - frameCount0) / elapsedTime);
frameTime0 = frameTime;
frameCount0 = frameCount;
}
}
};
FPS frameRate;
class CubicWorldApp : GuiApplication
{
driver = "OpenGL";
timerResolution = 120;
CubicWorldApp()
{
// FIXME: Without this setupGL() ends up in a separate GL context and defaultVAO is same as our MD VAO
UseSingleGLContext(true);
}
bool Cycle(bool idle)
{
cubicWorld.Update(null);
return true; //false;
}
}
class CubicWorld : Window
{
text = "Cubic World: A MultiDraw, ArrayTexture and Instancing Demo";
background = fogColor;
borderStyle = sizable;
hasMaximize = true;
hasMinimize = true;
hasClose = true;
state = maximized;
// glCapabilities.compatible = true;
Camera camera
{
// attachedQuaternion,
fixed,
position = Vector3D { 0, 0, -100 },
orientation = Euler { 120, 30, 0 },
zMin = 0.01f;
fov = 53;
};
CubeTris /*Cube*/ model { size = { 1, 1, 1 } };
bool moving, lightMoving;
Point startPosition;
Euler startOrientation;
Light light
{
diffuse = white;
specular = white;
orientation = Euler { pitch = 10, yaw = 30 };
};
CubicWorld()
{
int i;
for(i = 0; i < maxLoadedChunks; i++)
loadedChunks[i].index = -1;
freeChunks.init(maxLoadedChunks);
return true;
}
~CubicWorld()
{
int i;
for(i = 0; i < maxLoadedChunks; i++)
{
CubeChunk * chunk = &loadedChunks[i];
if(chunk->loaded)
chunk->unload();
}
}
void OnUnloadGraphics()
{
loadingThread.terminate();
model.Free(displaySystem);
displaySystem.ClearMaterials();
displaySystem.ClearTextures();
displaySystem.ClearMeshes();
}
void OnResize(int w, int h)
{
camera.Setup(w, h, null);
Update(null);
}
bool OnLeftButtonDown(int x, int y, Modifiers mods)
{
if(!moving && !lightMoving)
{
startPosition.x = x;
startPosition.y = y;
startOrientation = camera.orientation;
Capture();
moving = true;
}
return true;
}
bool OnLeftButtonUp(int x, int y, Modifiers mods)
{
if(moving)
{
ReleaseCapture();
moving = false;
}
return true;
}
bool OnRightButtonDown(int x, int y, Modifiers mods)
{
if(!moving && !lightMoving)
{
startPosition.x = x;
startPosition.y = y;
startOrientation = light.orientation;
Capture();
lightMoving = true;
}
return true;
}
bool OnRightButtonUp(int x, int y, Modifiers mods)
{
if(lightMoving)
{
ReleaseCapture();
lightMoving = false;
}
return true;
}
bool OnMouseMove(int x, int y, Modifiers mods)
{
if(moving)
{
Euler euler
{
startOrientation.yaw - (x - startPosition.x),
startOrientation.pitch + (y - startPosition.y),
startOrientation.roll
};
camera.orientation = euler;
Update(null);
}
else if(lightMoving)
{
light.orientation = Euler
{
startOrientation.yaw - (x - startPosition.x),
startOrientation.pitch + (y - startPosition.y),
startOrientation.roll
};
Update(null);
}
return true;
}
bool OnKeyDown(Key key, unichar ch)
{
switch(key)
{
case f: freeze ^= true; return false;
case escape: Destroy(0); return false;
}
return true;
}
bool OnKeyHit(Key key, unichar ch)
{
switch((SmartKey) key)
{
case right: camera.Move({ 1.0, 0, 0 }); Update(null); break;
case left: camera.Move({ -1.0, 0, 0 }); Update(null); break;
case down: case wheelDown: case minus: camera.Move({ 0, 0, -3.0 }); Update(null); break;
case up: case wheelUp: case plus: camera.Move({ 0, 0, 3.0 }); Update(null); break;
case pageDown: camera.Move({ 0, 1.0, 0 }); Update(null); break;
case pageUp: camera.Move({ 0, -1.0, 0 }); Update(null); break;
}
return true;
}
bool OnLoadGraphics()
{
setupGL(display);
PrintLn("We've got OpenGL Version: ", (char*)glGetString(GL_VERSION), "\n");
PrintLn("We've got OpenGL Renderer: ", (char*)glGetString(GL_RENDERER), "\n");
if(model.Create(null))
{
int t;
#if 0
ColorAlpha * palette = GetDefaultPalette();
ColorAlpha color = palette[t];
atTextures.init(1, 1, 1, numTextures);
atTextures.set1x1Layer(t, color, 0);
#else
const String tFiles[] = { "glass.bmp", "tex1.bmp", "tex2.bmp", "tex3.bmp", "tex4.bmp", "tex5.bmp", "tex6.bmp", "tex7.bmp", "tex8.bmp" };
atTextures.init(9, 256, 256, numTextures);
for(t = 0; t < numTextures; t++)
{
char path[MAX_LOCATION];
Bitmap bmp { };
sprintf(path, "../TransCube/%s", tFiles[t]);
bmp.Load(path, null, null);
model.mesh.UploadTexture(bmp, displaySystem, atTextures);
bmp.driverData = null;
bmp.Free();
delete bmp;
}
#endif
mdWorld.commandsCount = 1; // Avoids call to resize()
mdWorld.init(triangles, 1);
mdWorld.transformSize = 3;
model.Upload(displaySystem, mdWorld.vertexGLMB, mdWorld.indexGLMB, 1, &atTextures);
camera.target = model;
frameRate.Start();
loadingThread.setup(1, 6); // 6 chunk loading threads
return true;
}
return false;
}
void updatePosition(Vector3D cPos)
{
int64 cx = (int64)(cPos.x / CUBES_X + 0.5);
int64 cy = (int64)(cPos.y / CUBES_Y + 0.5);
int64 cz = (int64)(cPos.z / CUBES_Z + 0.5);
int64 v = viewDistance, v2 = v*v;
int64 hv = viewDistance/2, hv2 = hv*hv;
int64 d;
int64 ox, oy, oz;
int i;
Vector3D c;
for(i = 0; i < maxLoadedChunks; i++)
{
CubeChunk * chunk = &loadedChunks[i];
chunk->visible = false;
if(chunk->loaded)
{
ox = chunk->ox - cx, oy = chunk->oy - cy, oz = chunk->oz - cz;
d = ox * ox + oy * oy + oz * oz;
if(d > v2)
chunk->unload();
}
}
c.x = (cx - v) * CUBES_X;
for(ox = -v; ox <= v; ox++, c.x += CUBES_X)
{
Vector3D c { (cx + ox) * CUBES_X, (cy + oy) * CUBES_Y, (cz + oz) * CUBES_Z };
c.y = (cy - v) * CUBES_Z;
for(oy = -v; oy <= v; oy++, c.y += CUBES_Y)
{
c.z = (cz - v) * CUBES_Z;
for(oz = -v; oz <= v; oz++, c.z += CUBES_Z)
{
int64 d = ox * ox + oy * oy + oz * oz;
if(d <= v2)
{
bool visible = camera.PointsVisible(c, 1, CUBES_X/2);
if(visible || d < hv)
CubeChunk::ensure(cx + ox, cy + oy, cz + oz, visible);
}
}
}
}
}
void OnRedraw(Surface surface)
{
Vector3D cPos;
int i;
setupGL(display);
surface.Clear(depthBuffer);
camera.Update();
cPos = camera.cPosition;
display.antiAlias = true;
GLMultisampling(true);
display.SetCamera(surface, camera);
if(!freeze)
updatePosition(cPos);
butterburShader.select();
butterburShader.setLight(cPos, 0, light);
butterburShader.setFogColor(fogColor.r / 255.0f, fogColor.g / 255.0f, fogColor.b / 255.0f); //0.2, 0.2, 0.8);
butterburShader.setFogDensity(fogDensity);
butterburShader.fog(true);
butterburShader.multiDraw(true);
butterburShader.setSimpleMaterial(white, false);
butterburShader.lighting(true);
butterburShader.texturing(true);
butterburShader.textureArray(true);
butterburShader.transform3D = false; // This should be renamed 'fullTransform3D' -- false because we only have x,y,z offset
butterburShader.setGlobalAmbient(0.2f, 0.2f, 0.2f, 1.0f);
atTextures.bind();
glEnable(GL_CULL_FACE);
for(i = 0; i < maxLoadedChunks; i++)
{
CubeChunk * chunk = &loadedChunks[i];
if(chunk->visible && chunk->loaded)
chunk->draw(cPos);
}
#if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3)
if(glCaps_vao) glBindVertexArray(defaultVAO);
#endif
GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
DefaultShader::shader().select();
display.SetCamera(surface, null);
surface.foreground = white;
surface.WriteTextf(10,10, "FPS: %.02f", frameRate.fps);
frameRate.Step();
}
}
{
"Version" : 0.2,
"ModuleName" : "CubicWorld",
"Options" : {
"MemoryGuard" : false,
"Profile" : false,
"Optimization" : "None",
"PreprocessorDefinitions" : [
"IMPORT_STATIC=\"\""
],
"IncludeDirs" : [
"$(ECERE_SDK_SRC)/ecere/src/gfx/drivers/gl3"
],
"StrictNameSpaces" : false,
"TargetType" : "Executable",
"TargetFileName" : "CubicWorld",
"Libraries" : [
"ecere"
],
"Console" : false
},
"Platforms" : [
{
"Name" : "linux",
"Options" : {
"Libraries" : [
"m",
"GL"
]
}
},
{
"Name" : "apple",
"Options" : {
"Libraries" : [
"m"
]
}
},
{
"Name" : "win32",
"Options" : {
"Libraries" : [
"opengl32"
]
}
}
],
"Configurations" : [
{
"Name" : "Debug",
"Options" : {
"Debug" : true,
"Optimization" : "None"
}
},
{
"Name" : "Release",
"Options" : {
"Debug" : true,
"Optimization" : "Speed",
"FastMath" : true
}
}
],
"Files" : [
{
"Folder" : "butterbur",
"Files" : [
{
"Folder" : "opengl",
"Files" : [
"$(ECERE_SDK_SRC)/butterbur/src/opengl/ButterburShader.ec",
"$(ECERE_SDK_SRC)/butterbur/src/opengl/VersionedShader.ec",
"$(ECERE_SDK_SRC)/ecere/src/gfx/drivers/gl3/gl_compat_4_4.c",
"$(ECERE_SDK_SRC)/ecere/src/gfx/drivers/gl3/gl_compat_4_4.h"
]
}
]
},
"cubicWorld.ec",
"mandelbulb.ec",
"cubeTris.ec",
"$(ECERE_SDK_SRC)/extras/threadedProcessing.ec"
],
"ResourcesPath" : "",
"Resources" : [
{
"Folder" : "shaders",
"Files" : [
"$(ECERE_SDK_SRC)/butterbur/src/opengl/shaders/butterbur.frag",
"$(ECERE_SDK_SRC)/butterbur/src/opengl/shaders/butterbur.vert"
]
}
]
}
import "ecere"
double epsilon = 0.001;
struct HyperComplex
{
double a, b, c;
};
struct Mandelbulb
{
Vector3D size;
double power;
int isPointInside(Vector3Df p, int iters)
{
HyperComplex Z { };
HyperComplex C { p.x * 4 / size.x, p.y * 4 / size.y, p.z * 4 / size.z};
int i;
double zm;
for(i = 0; i < iters; i++)
{
if(i > 0)
{
double theta = atan2(sqrt(Z.a*Z.a + Z.b*Z.b), Z.c) * power;
double phi = atan2(Z.b, Z.a) * power;
double raised = zm*zm*zm*zm*zm*zm*zm*zm;
double sinT = sin(theta);
Z.a = raised * sinT * cos(phi) + C.a;
Z.b = raised * sinT * sin(phi) + C.b;
Z.c = raised * cos(theta) + C.c;
}
else
Z = C;
zm = 1.0 / FastInvSqrtDouble(Z.a * Z.a + Z.b * Z.b + Z.c * Z.c);
if(zm - epsilon >= 2)
return 0;
}
return (int)(zm * 5);
}
};
@jerstlouis
Copy link
Author

cubes

@jerstlouis
Copy link
Author

cubes2

@jerstlouis
Copy link
Author

maldelbulbCubes

@jerstlouis
Copy link
Author

jerstlouis commented Oct 31, 2022

mandelbulbCubes3

@jerstlouis
Copy link
Author

mandelbulbs

@jerstlouis
Copy link
Author

manyMandelbulbs

@jerstlouis
Copy link
Author

infiniteMandelbulbs

@jerstlouis
Copy link
Author

fixedFog

@jerstlouis
Copy link
Author

mandelbulbsFinal

@jerstlouis
Copy link
Author

improvedFog

@jerstlouis
Copy link
Author

multiMandelbulb

@jerstlouis
Copy link
Author

mandelbulbHigh

@jerstlouis
Copy link
Author

mandelbulbRose

@jerstlouis
Copy link
Author

mandelbulbOne

@jerstlouis
Copy link
Author

mandelbulbCool

@jerstlouis
Copy link
Author

mandelbulbPool

@jerstlouis
Copy link
Author

holyMandelbulb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment