548 lines
12 KiB
C++
548 lines
12 KiB
C++
#include <GL/glut.h>
|
|
#include <vector>
|
|
#include <math.h>
|
|
|
|
#include "PerlinNoise.hpp"
|
|
#include "libs/mainloop-api/mainloop.h"
|
|
#include "archive.h"
|
|
#include "textures.h"
|
|
#include "blocks.h"
|
|
|
|
int blocks_tex;
|
|
int blocks_size;
|
|
int blocks_img_size[2];
|
|
double fluid_motion = 0;
|
|
double fluid_frequency = 0.99*8;
|
|
double fluid_octaves = 1;
|
|
|
|
std::vector<BlockSettings> block_settings;
|
|
|
|
const siv::PerlinNoise perlin;
|
|
|
|
BlockSettings blockGetSettings(int id) {
|
|
return block_settings[id];
|
|
}
|
|
|
|
int load_image(const char* dir)
|
|
{
|
|
int w, h;
|
|
loadArchiveImageGL(dir, 'N', w, h);
|
|
}
|
|
|
|
void blocks_tick(int *args)
|
|
{
|
|
// Make this happen again
|
|
mainloopRegAction(blocks_tick, 10, 0);
|
|
|
|
// Increase the fluid time for perlin noise
|
|
fluid_motion += 1e-2;
|
|
}
|
|
|
|
void setup_block_settings()
|
|
{
|
|
BlockSettings b;
|
|
|
|
// Set all the textures numbers
|
|
int GRASS_TOP = 0;
|
|
int GRASS_SIDE = 1;
|
|
int ASPHELT_TOP = 2;
|
|
int ASPHELT_SIDE = 3;
|
|
int DIRT = 4;
|
|
int GRAVEL = 5;
|
|
int STONE = 6;
|
|
int BARRIER = 7;
|
|
int PLANT_GRASS = 8;
|
|
int WATER = 9;
|
|
int SAND = 10;
|
|
|
|
// Create the queue of textures to load
|
|
std::vector<const char*> load_images;
|
|
load_images.push_back("textures/blocks/grass_top.rimg");
|
|
load_images.push_back("textures/blocks/grass_side.rimg");
|
|
load_images.push_back("textures/blocks/asphelt_top.rimg");
|
|
load_images.push_back("textures/blocks/asphelt_side.rimg");
|
|
load_images.push_back("textures/blocks/dirt.rimg");
|
|
load_images.push_back("textures/blocks/gravel.rimg");
|
|
load_images.push_back("textures/blocks/stone.rimg");
|
|
load_images.push_back("textures/blocks/barrier.rimg");
|
|
load_images.push_back("textures/plants/grass.rimg");
|
|
load_images.push_back("textures/fluids/water.rimg");
|
|
load_images.push_back("textures/blocks/sand.rimg");
|
|
|
|
// Setup the big image
|
|
int big_image_size;
|
|
char* big_image;
|
|
|
|
// Loop over the queue
|
|
for(int i=0;i<load_images.size();i++)
|
|
{
|
|
// Get the image position
|
|
ArchivePos pos = archiveGetPos(archive, load_images[i]);
|
|
|
|
// Get the image
|
|
char* tex = new char[pos.size];
|
|
archiveRead(archive, pos, tex);
|
|
|
|
// Is this the first iteration
|
|
if(i==0)
|
|
{
|
|
// Set the big image to the texture
|
|
big_image = tex;
|
|
big_image_size = pos.size;
|
|
}
|
|
|
|
else
|
|
{
|
|
// Combine the images
|
|
int new_image_size;
|
|
char* new_image = combineImages(big_image, big_image_size, tex, pos.size, new_image_size);
|
|
|
|
// Free the old texture data
|
|
free(tex);
|
|
free(big_image);
|
|
|
|
// Set the new image as the big image
|
|
big_image = new_image;
|
|
big_image_size = new_image_size;
|
|
}
|
|
}
|
|
|
|
// Load the combined blocks texture
|
|
blocks_tex = loadImageDataGL(big_image, big_image_size, 'N',
|
|
blocks_img_size[0], blocks_img_size[1]);
|
|
|
|
// Set the size of the textures to the width of the image
|
|
blocks_size = blocks_img_size[0];
|
|
|
|
// Air
|
|
b.transparent = true;
|
|
block_settings.push_back(b);
|
|
|
|
// Stone
|
|
b.tex.t = STONE;
|
|
b.tex.b = STONE;
|
|
b.tex.n = STONE;
|
|
b.tex.e = STONE;
|
|
b.tex.s = STONE;
|
|
b.tex.w = STONE;
|
|
b.transparent = false;
|
|
block_settings.push_back(b);
|
|
|
|
// Grass
|
|
b.tex.t = GRASS_TOP;
|
|
b.tex.b = DIRT;
|
|
b.tex.n = GRASS_SIDE;
|
|
b.tex.e = GRASS_SIDE;
|
|
b.tex.s = GRASS_SIDE;
|
|
b.tex.w = GRASS_SIDE;
|
|
b.transparent = false;
|
|
block_settings.push_back(b);
|
|
|
|
// Dirt
|
|
b.tex.t = DIRT;
|
|
b.tex.b = DIRT;
|
|
b.tex.n = DIRT;
|
|
b.tex.e = DIRT;
|
|
b.tex.s = DIRT;
|
|
b.tex.w = DIRT;
|
|
b.transparent = false;
|
|
block_settings.push_back(b);
|
|
|
|
// Gravel
|
|
b.tex.t = GRAVEL;
|
|
b.tex.b = GRAVEL;
|
|
b.tex.n = GRAVEL;
|
|
b.tex.e = GRAVEL;
|
|
b.tex.s = GRAVEL;
|
|
b.tex.w = GRAVEL;
|
|
b.transparent = false;
|
|
block_settings.push_back(b);
|
|
|
|
// Asphelt
|
|
b.tex.t = ASPHELT_TOP;
|
|
b.tex.b = DIRT;
|
|
b.tex.n = ASPHELT_SIDE;
|
|
b.tex.e = ASPHELT_SIDE;
|
|
b.tex.s = ASPHELT_SIDE;
|
|
b.tex.w = ASPHELT_SIDE;
|
|
b.transparent = false;
|
|
block_settings.push_back(b);
|
|
|
|
// Barrier
|
|
b.tex.t = BARRIER;
|
|
b.tex.b = BARRIER;
|
|
b.tex.n = BARRIER;
|
|
b.tex.e = BARRIER;
|
|
b.tex.s = BARRIER;
|
|
b.tex.w = BARRIER;
|
|
b.transparent = true;
|
|
block_settings.push_back(b);
|
|
|
|
// Grass Plant
|
|
b.tex.t = PLANT_GRASS;
|
|
b.tex.b = PLANT_GRASS;
|
|
b.transparent = true;
|
|
block_settings.push_back(b);
|
|
|
|
// Water
|
|
b.tex.t = WATER;
|
|
b.tex.b = WATER;
|
|
b.tex.n = WATER;
|
|
b.tex.e = WATER;
|
|
b.tex.s = WATER;
|
|
b.tex.w = WATER;
|
|
b.transparent = true;
|
|
block_settings.push_back(b);
|
|
|
|
// Sand
|
|
b.tex.t = SAND;
|
|
b.tex.b = SAND;
|
|
b.tex.n = SAND;
|
|
b.tex.e = SAND;
|
|
b.tex.s = SAND;
|
|
b.tex.w = SAND;
|
|
b.transparent = false;
|
|
block_settings.push_back(b);
|
|
}
|
|
|
|
Block make_block(uint8_t id, uint8_t type, uint8_t direction)
|
|
{
|
|
// Set the values
|
|
Block b;
|
|
b.id = id;
|
|
b.type = type;
|
|
b.direction = direction;
|
|
|
|
// Return the block
|
|
return b;
|
|
}
|
|
|
|
void blocks_init()
|
|
{
|
|
// Set the size of the block textures
|
|
blocks_size = blocks_img_size[0]/3;
|
|
|
|
// Initialise the default blocks
|
|
setup_block_settings();
|
|
|
|
// Register some actions
|
|
mainloopRegAction(blocks_tick, 10, 0);
|
|
}
|
|
|
|
void tex_coord_block(double x, double y)
|
|
{
|
|
// Load the position of a texture on a list of textures
|
|
glTexCoord2d(x, y*blocks_size/((double)blocks_img_size[1]));
|
|
}
|
|
|
|
void bind_block_texture()
|
|
{
|
|
// Bind the texture
|
|
glBindTexture(GL_TEXTURE_2D, blocks_tex);
|
|
}
|
|
|
|
void unbind_block_texture()
|
|
{
|
|
// Unbind the texture
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
void render_block_face_here(Block block)
|
|
{
|
|
// Get the texture settings
|
|
BlockTextures bt = block_settings[block.id].tex;
|
|
|
|
unbind_block_texture();
|
|
|
|
// Render the face
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
/*tex_coord_block(0, bt.n+0); */glVertex2d(-1,-1);
|
|
/*tex_coord_block(1, bt.n+0); */glVertex2d( 1,-1);
|
|
/*tex_coord_block(1, bt.n+1); */glVertex2d( 1, 1);
|
|
/*tex_coord_block(0, bt.n+1); */glVertex2d(-1, 1);
|
|
}
|
|
|
|
double get_fluid_motion(int x, int z)
|
|
{
|
|
// Return the blocks perlin noise
|
|
return perlin.octaveNoise0_1(
|
|
x / fluid_frequency,
|
|
z / fluid_frequency,
|
|
fluid_motion,
|
|
fluid_octaves
|
|
)*2;
|
|
}
|
|
|
|
void render_block(Block block, int x, int y, int z, BlockFaceMap fm)
|
|
{
|
|
// Save the current matrix
|
|
glPushMatrix();
|
|
|
|
// Shift the block face map
|
|
for(int i=0;i<block.direction;i++)
|
|
{
|
|
// Save some of the values of the faces to show
|
|
bool n = fm.n;
|
|
bool e = fm.e;
|
|
bool s = fm.s;
|
|
bool w = fm.w;
|
|
|
|
// Load them moved slightly
|
|
fm.n = w;
|
|
fm.e = n;
|
|
fm.s = e;
|
|
fm.w = s;
|
|
}
|
|
|
|
// Set the blocks position
|
|
|
|
// North
|
|
if(block.direction==DIRECTION_N) {
|
|
glTranslatef(x,y,z);
|
|
}
|
|
|
|
// East
|
|
if(block.direction==DIRECTION_E) {
|
|
glTranslatef(x,y,z+1);
|
|
}
|
|
|
|
// South
|
|
if(block.direction==DIRECTION_S) {
|
|
glTranslatef(x+1,y,z+1);
|
|
}
|
|
|
|
// West
|
|
if(block.direction==DIRECTION_W) {
|
|
glTranslatef(x+1,y,z);
|
|
}
|
|
|
|
// Rotate the block
|
|
glRotatef(block.direction*90,0,1,0);
|
|
|
|
BlockTextures bt = block_settings[block.id].tex;
|
|
|
|
// Is this a plant type
|
|
if(block.type == BTYPE_PLANT)
|
|
{
|
|
// Start drawing
|
|
glBegin(GL_QUADS);
|
|
|
|
// Draw in an X shape
|
|
tex_coord_block(0, bt.t+1); glVertex3i(1,0,1);
|
|
tex_coord_block(0, bt.t+0); glVertex3i(1,1,1);
|
|
tex_coord_block(1, bt.t+0); glVertex3i(0,1,0);
|
|
tex_coord_block(1, bt.t+1); glVertex3i(0,0,0);
|
|
|
|
tex_coord_block(0, bt.b+1); glVertex3i(1,0,0);
|
|
tex_coord_block(0, bt.b+0); glVertex3i(1,1,0);
|
|
tex_coord_block(1, bt.b+0); glVertex3i(0,1,1);
|
|
tex_coord_block(1, bt.b+1); glVertex3i(0,0,1);
|
|
|
|
// Stop drawing
|
|
glEnd();
|
|
|
|
// Pop the old matrix
|
|
glPopMatrix();
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Start drawing
|
|
glBegin(GL_QUADS);
|
|
|
|
// Block type
|
|
if(block.type == BTYPE_BLOCK)
|
|
{
|
|
// Top
|
|
if(fm.t)
|
|
{
|
|
tex_coord_block(0, bt.t+0); glVertex3i(0,1,0);
|
|
tex_coord_block(1, bt.t+0); glVertex3i(1,1,0);
|
|
tex_coord_block(1, bt.t+1); glVertex3i(1,1,1);
|
|
tex_coord_block(0, bt.t+1); glVertex3i(0,1,1);
|
|
}
|
|
|
|
// Sides
|
|
|
|
if(fm.s)
|
|
{
|
|
tex_coord_block(0, bt.s+0); glVertex3i(1,1,1);
|
|
tex_coord_block(1, bt.s+0); glVertex3i(0,1,1);
|
|
tex_coord_block(1, bt.s+1); glVertex3i(0,0,1);
|
|
tex_coord_block(0, bt.s+1); glVertex3i(1,0,1);
|
|
}
|
|
|
|
if(fm.w)
|
|
{
|
|
tex_coord_block(1, bt.w+0); glVertex3i(0,1,1);
|
|
tex_coord_block(1, bt.w+1); glVertex3i(0,0,1);
|
|
tex_coord_block(0, bt.w+1); glVertex3i(0,0,0);
|
|
tex_coord_block(0, bt.w+0); glVertex3i(0,1,0);
|
|
}
|
|
|
|
if(fm.e)
|
|
{
|
|
tex_coord_block(1, bt.e+0); glVertex3i(1,1,1);
|
|
tex_coord_block(1, bt.e+1); glVertex3i(1,0,1);
|
|
tex_coord_block(0, bt.e+1); glVertex3i(1,0,0);
|
|
tex_coord_block(0, bt.e+0); glVertex3i(1,1,0);
|
|
}
|
|
}
|
|
|
|
// Ramp type
|
|
if(block.type == BTYPE_RAMP)
|
|
{
|
|
// Top
|
|
if(fm.t)
|
|
{
|
|
tex_coord_block(0, bt.t+0); glVertex3i(0,1,0);
|
|
tex_coord_block(1, bt.t+0); glVertex3i(1,1,0);
|
|
tex_coord_block(1, bt.t+1); glVertex3i(1,0,1);
|
|
tex_coord_block(0, bt.t+1); glVertex3i(0,0,1);
|
|
}
|
|
}
|
|
|
|
// Bottom
|
|
if(fm.b)
|
|
{
|
|
tex_coord_block(0, bt.b+0); glVertex3i(0,0,0);
|
|
tex_coord_block(1, bt.b+0); glVertex3i(1,0,0);
|
|
tex_coord_block(1, bt.b+1); glVertex3i(1,0,1);
|
|
tex_coord_block(0, bt.b+1); glVertex3i(0,0,1);
|
|
}
|
|
|
|
// Back
|
|
if(fm.n && (block.type == BTYPE_RAMP || block.type == BTYPE_BLOCK))
|
|
{
|
|
tex_coord_block(0, bt.n+0); glVertex3i(1,1,0);
|
|
tex_coord_block(1, bt.n+0); glVertex3i(0,1,0);
|
|
tex_coord_block(1, bt.n+1); glVertex3i(0,0,0);
|
|
tex_coord_block(0, bt.n+1); glVertex3i(1,0,0);
|
|
}
|
|
|
|
// Fluids
|
|
if(block.type == BTYPE_FLUID)
|
|
{
|
|
// Height varible
|
|
double h;
|
|
|
|
// Frequency
|
|
double f = fluid_frequency;
|
|
|
|
// Octaves
|
|
double o = fluid_octaves;
|
|
|
|
// Is there free space above
|
|
if(fm.t)
|
|
{
|
|
// Calculate the height of the fluid
|
|
h = perlin.octaveNoise0_1(x / f, z / f, fluid_motion, o);
|
|
}
|
|
|
|
else
|
|
{
|
|
// Set the height to maximum
|
|
h = 1;
|
|
}
|
|
|
|
// Top
|
|
if(fm.t)
|
|
{
|
|
/*for(int bx=-1;bx<2;bx++)
|
|
{
|
|
for(int bz=-1;bz<2;bz++)
|
|
{
|
|
tex_coord_block(0, bt.t+0); glVertex3d(bx+0,1*h,bz+0);
|
|
tex_coord_block(1, bt.t+0); glVertex3d(bx+1,1*h,bz+0);
|
|
tex_coord_block(1, bt.t+1); glVertex3d(bx+1,1*h,bz+1);
|
|
tex_coord_block(0, bt.t+1); glVertex3d(bx+0,1*h,bz+1);
|
|
}
|
|
}*/
|
|
|
|
tex_coord_block(0, bt.t+0); glVertex3f(0,1*h,0);
|
|
tex_coord_block(1, bt.t+0); glVertex3f(1,1*h,0);
|
|
tex_coord_block(1, bt.t+1); glVertex3f(1,1*h,1);
|
|
tex_coord_block(0, bt.t+1); glVertex3f(0,1*h,1);
|
|
}
|
|
|
|
// Sides
|
|
|
|
// N
|
|
if(fm.t || fm.n)
|
|
{
|
|
double nh;
|
|
if(fm.w) nh = 0;
|
|
else nh = perlin.octaveNoise0_1(x / f, (z-1) / f, fluid_motion, o);
|
|
tex_coord_block(0, bt.s+0+nh); glVertex3f(1,1*h,0);
|
|
tex_coord_block(1, bt.s+0+nh); glVertex3f(0,1*h,0);
|
|
tex_coord_block(1, bt.s+1*h); glVertex3f(0,0+nh,0);
|
|
tex_coord_block(0, bt.s+1*h); glVertex3f(1,0+nh,0);
|
|
}
|
|
|
|
// S
|
|
if(fm.s)
|
|
{
|
|
double nh = 0;
|
|
tex_coord_block(0, bt.s+0+nh); glVertex3f(1,1*h,1);
|
|
tex_coord_block(1, bt.s+0+nh); glVertex3f(0,1*h,1);
|
|
tex_coord_block(1, bt.s+1*h); glVertex3f(0,0+nh,1);
|
|
tex_coord_block(0, bt.s+1*h); glVertex3f(1,0+nh,1);
|
|
}
|
|
|
|
// W
|
|
if(fm.t || fm.w)
|
|
{
|
|
double nh;
|
|
if(fm.w) nh = 0;
|
|
else nh = perlin.octaveNoise0_1((x-1) / f, z / f, fluid_motion, o);
|
|
tex_coord_block(1, bt.w+0+nh); glVertex3f(0,1*h,1);
|
|
tex_coord_block(1, bt.w+1*h); glVertex3f(0,0+nh,1);
|
|
tex_coord_block(0, bt.w+1*h); glVertex3f(0,0+nh,0);
|
|
tex_coord_block(0, bt.w+0+nh); glVertex3f(0,1*h,0);
|
|
}
|
|
|
|
// E
|
|
if(fm.e)
|
|
{
|
|
double nh = 0;
|
|
tex_coord_block(1, bt.e+0+nh); glVertex3f(1,1*h,1);
|
|
tex_coord_block(1, bt.e+1*h); glVertex3f(1,0+nh,1);
|
|
tex_coord_block(0, bt.e+1*h); glVertex3f(1,0+nh,0);
|
|
tex_coord_block(0, bt.e+0+nh); glVertex3f(1,1*h,0);
|
|
}
|
|
}
|
|
|
|
// Stop drawing
|
|
glEnd();
|
|
|
|
// Ramp type
|
|
if(block.type==BTYPE_RAMP)
|
|
{
|
|
// Start drawing triangles
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
// Sides
|
|
|
|
if(fm.w)
|
|
{
|
|
tex_coord_block(1, bt.e+1); glVertex3i(0,0,1);
|
|
tex_coord_block(0, bt.e+1); glVertex3i(0,0,0);
|
|
tex_coord_block(0, bt.e+0); glVertex3i(0,1,0);
|
|
}
|
|
|
|
if(fm.e)
|
|
{
|
|
tex_coord_block(1, bt.e+1); glVertex3i(1,0,1);
|
|
tex_coord_block(0, bt.e+1); glVertex3i(1,0,0);
|
|
tex_coord_block(0, bt.e+0); glVertex3i(1,1,0);
|
|
}
|
|
|
|
// Stop drawing
|
|
glEnd();
|
|
}
|
|
|
|
// Pop the old matrix
|
|
glPopMatrix();
|
|
}
|