first commit

This commit is contained in:
jsrobson10 2019-05-25 14:24:49 +10:00
parent bd42545e39
commit 474aa4e72e
65 changed files with 6060 additions and 0 deletions

74
Makefile Normal file
View File

@ -0,0 +1,74 @@
OUTPUT=src/blockracer
FILES=blockracer.o mainloop.o graphics.o input.o gamepad.o\
player.o world.o blocks.o textures.o math.o text.o archive.o\
compression.o random.o clouds.o
ARGS=-c $< -o $@
CC=g++
all: $(OUTPUT)
$(OUTPUT): src $(FILES)# $(RESOURCES)
$(CC) $(FILES) -o $@ -lglut -lGL -lGLU -lX11 -lm -ludev -lz
src/resources:
mkdir src/resources
src:
mkdir src
blockracer.o: blockracer.cpp mainloop.h graphics.h input.h player.h world.h text.h archive.h clouds.h
$(CC) $(ARGS)
mainloop.o: mainloop.cpp
$(CC) $(ARGS)
graphics.o: graphics.cpp mainloop.h graphics.h player.h world.h textures.h clouds.h
$(CC) $(ARGS)
input.o: input.cpp input.h gamepad.h mainloop.h
$(CC) $(ARGS)
gamepad.o: gamepad.c gamepad.h
gcc $(ARGS) -Wall -Werror
player.o: player.cpp player.h input.h mainloop.h world.h textures.h blocks.h
$(CC) $(ARGS)
world.o: world.cpp world.h graphics.h blocks.h math.h player.h random.h
$(CC) $(ARGS)
blocks.o: blocks.cpp blocks.h textures.h archive.h mainloop.h
$(CC) $(ARGS)
textures.o: textures.cpp textures.h archive.h
$(CC) $(ARGS)
math.o: math.cpp math.h
$(CC) $(ARGS)
text.o: text.cpp textures.h
$(CC) $(ARGS)
archive.o: archive.cpp archive.h compression.h
$(CC) $(ARGS)
compression.o: compression.cpp compression.h zlib.h
$(CC) $(ARGS)
random.o: random.cpp random.h
$(CC) $(ARGS)
clouds.o: clouds.cpp clouds.h math.h textures.h random.h mainloop.h
$(CC) $(ARGS)
clean:
rm -r src *.o
run:
cd src && ./blockracer
backup:
cd .. && ./backup.sh
archive: resources
cd .. && ./make-archive.sh

219
PerlinNoise.hpp Normal file
View File

@ -0,0 +1,219 @@
//----------------------------------------------------------------------------------------
//
// siv::PerlinNoise
// Perlin noise library for modern C++
//
// Copyright (C) 2013-2018 Ryo Suzuki <reputeless@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//----------------------------------------------------------------------------------------
# pragma once
# include <cstdint>
# include <numeric>
# include <algorithm>
# include <random>
namespace siv
{
class PerlinNoise
{
private:
std::int32_t p[512];
static double Fade(double t) noexcept
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
static double Lerp(double t, double a, double b) noexcept
{
return a + t * (b - a);
}
static double Grad(std::int32_t hash, double x, double y, double z) noexcept
{
const std::int32_t h = hash & 15;
const double u = h < 8 ? x : y;
const double v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
public:
explicit PerlinNoise(std::uint32_t seed = std::default_random_engine::default_seed)
{
reseed(seed);
}
template <class URNG>
explicit PerlinNoise(URNG& urng)
{
reseed(urng);
}
void reseed(std::uint32_t seed)
{
for (size_t i = 0; i < 256; ++i)
{
p[i] = i;
}
std::shuffle(std::begin(p), std::begin(p) + 256, std::default_random_engine(seed));
for (size_t i = 0; i < 256; ++i)
{
p[256 + i] = p[i];
}
}
template <class URNG>
void reseed(URNG& urng)
{
for (size_t i = 0; i < 256; ++i)
{
p[i] = i;
}
std::shuffle(std::begin(p), std::begin(p) + 256, urng);
for (size_t i = 0; i < 256; ++i)
{
p[256 + i] = p[i];
}
}
double noise(double x) const
{
return noise(x, 0.0, 0.0);
}
double noise(double x, double y) const
{
return noise(x, y, 0.0);
}
double noise(double x, double y, double z) const
{
const std::int32_t X = static_cast<std::int32_t>(std::floor(x)) & 255;
const std::int32_t Y = static_cast<std::int32_t>(std::floor(y)) & 255;
const std::int32_t Z = static_cast<std::int32_t>(std::floor(z)) & 255;
x -= std::floor(x);
y -= std::floor(y);
z -= std::floor(z);
const double u = Fade(x);
const double v = Fade(y);
const double w = Fade(z);
const std::int32_t A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z;
const std::int32_t B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;
return Lerp(w, Lerp(v, Lerp(u, Grad(p[AA], x, y, z),
Grad(p[BA], x - 1, y, z)),
Lerp(u, Grad(p[AB], x, y - 1, z),
Grad(p[BB], x - 1, y - 1, z))),
Lerp(v, Lerp(u, Grad(p[AA + 1], x, y, z - 1),
Grad(p[BA + 1], x - 1, y, z - 1)),
Lerp(u, Grad(p[AB + 1], x, y - 1, z - 1),
Grad(p[BB + 1], x - 1, y - 1, z - 1))));
}
double octaveNoise(double x, std::int32_t octaves) const
{
double result = 0.0;
double amp = 1.0;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += noise(x) * amp;
x *= 2.0;
amp *= 0.5;
}
return result;
}
double octaveNoise(double x, double y, std::int32_t octaves) const
{
double result = 0.0;
double amp = 1.0;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += noise(x, y) * amp;
x *= 2.0;
y *= 2.0;
amp *= 0.5;
}
return result;
}
double octaveNoise(double x, double y, double z, std::int32_t octaves) const
{
double result = 0.0;
double amp = 1.0;
for (std::int32_t i = 0; i < octaves; ++i)
{
result += noise(x, y, z) * amp;
x *= 2.0;
y *= 2.0;
z *= 2.0;
amp *= 0.5;
}
return result;
}
double noise0_1(double x) const
{
return noise(x) * 0.5 + 0.5;
}
double noise0_1(double x, double y) const
{
return noise(x, y) * 0.5 + 0.5;
}
double noise0_1(double x, double y, double z) const
{
return noise(x, y, z) * 0.5 + 0.5;
}
double octaveNoise0_1(double x, std::int32_t octaves) const
{
return octaveNoise(x, octaves) * 0.5 + 0.5;
}
double octaveNoise0_1(double x, double y, std::int32_t octaves) const
{
return octaveNoise(x, y, octaves) * 0.5 + 0.5;
}
double octaveNoise0_1(double x, double y, double z, std::int32_t octaves) const
{
return octaveNoise(x, y, z, octaves) * 0.5 + 0.5;
}
};
}

345
archive.cpp Normal file
View File

@ -0,0 +1,345 @@
#include <vector>
#include <string>
#include <fstream>
#include <streambuf>
#include <cstring>
#include "archive.h"
#include "compression.h"
std::vector<std::string> archives;
int archive;
void stringRead(std::string str, int* pos, char* data, int size)
{
// Loop over part of the string
for(int i = 0; i < size && i < str.size(); i++)
{
// Set part of the data to part of the string
data[i] = str[*pos+i];
}
// Add to the position
*pos += size;
}
void stringWrite(std::string &str, const char* data, int size)
{
// Loop over the data
for(int i = 0; i < size; i++)
{
// Add it to the string
str += data[i];
}
}
int archiveGen(const char* data, int size, bool compression)
{
// Create the loaded archive data file
std::string sdata;
// Is there decompression needed
if(compression)
{
// Get the size of the uncompressed string
uint64_t csize;
// Decompress the string
const char* cdata = decompress_string(data, size, &csize);
// Load the archives data
sdata.append(cdata, csize);
}
else
{
// Load the archives data
sdata.append(data, size);
}
// Push back the archive
archives.push_back(sdata);
// Return the archives position
return archives.size()-1;
}
int archiveLoad(const char* dir, bool compression)
{
// Open the file
std::ifstream file(dir, std::ios::binary);
// Is the file good
if(file.good())
{
// Read the data
std::istreambuf_iterator<char> begin(file), end;
std::string data(begin, end);
// Is there decompression needed
if(compression)
{
// Convert the string to a c string
int csize = data.size();
char* cdata = new char[csize];
// Loop over the string
for(int i=0;i<csize;i++)
{
// Push the string item to the cstring
cdata[i] = data[i];
}
// Get the decompressed size
uint64_t nsize;
// Clear the data varible
data = "";
// Decompress the data
const char* ndata = decompress_string(cdata, csize, &nsize);
data.append(ndata, nsize);
}
// Push back the archive
archives.push_back(data);
// Return the archives position
return archives.size()-1;
}
else
{
// Return an error message, -1
return -1;
}
}
const char* archiveGetData(int a, uint64_t* size, bool compression)
{
// Get the data
const char* data = archives[a].c_str();
uint64_t dsize = archives[a].size();
// Does the user want compression
if(compression)
{
// Return compressed data
return compress_string(data, dsize, size);
}
else
{
// Set the size
*size = dsize;
// Return the normal data
return data;
}
}
bool archiveSave(int a, const char* dir, bool compression)
{
// Open the file
std::ofstream file(dir, std::ios::binary);
// Is the file good
if(file.good())
{
// Is there compression
if(compression)
{
// Convert string to a c string
uint64_t c_size = archives[a].size();
char* c_str = new char[c_size];
// Loop over the string
for(int i=0;i<c_size;i++)
{
// Push the string element to the c string
c_str[i] = archives[a][i];
}
// Get the compressed size
uint64_t csize;
// Get the compressed data
const char* cdata = compress_string(c_str, c_size, &csize);
// Write the compressed data to the file
file.write(cdata, csize);
}
else
{
// Write the archive to the file
file.write(archives[a].c_str(), archives[a].size());
}
// Close the file
file.close();
// Return true
return true;
}
else
{
// Close the file
file.close();
// Return false
return false;
}
}
void archiveFree(int a)
{
// Delete the archives reference
delete &archives[a];
}
ArchivePos archiveGetEnd()
{
// Create the position
ArchivePos pos;
pos.end = true;
pos.found = false;
// Return the position
return pos;
}
ArchivePos archiveGetPos(int a, const char* dir)
{
// Loop over the archive
int i=0;
while(i<archives[a].size())
{
// Get the name size
uint32_t namesize;
stringRead(archives[a], &i, (char*)&namesize, sizeof(namesize));
// Get the name
char* name = new char[namesize];
stringRead(archives[a], &i, name, namesize);
// Get the data size
uint32_t datasize;
stringRead(archives[a], &i, (char*)&datasize, sizeof(datasize));
// Does the name size equal the directory name size
if(namesize == strlen(dir))
{
// Check if both files are the same
bool same = true;
// Loop over the name size
for(int i=0;i<namesize;i++)
{
// Do the names not match
if(name[i] != dir[i])
{
// Set same to false
same = false;
}
}
// Are the directories the same
if(same)
{
// Set the position
ArchivePos pos;
pos.end = false;
pos.found = true;
pos.size = datasize;
pos.pos = i;
// Return the position
return pos;
}
}
// Free the name
free(name);
// Skip the datas bytes
i += datasize;
}
// Set the position
ArchivePos pos;
pos.found = false;
pos.end = true;
// Return the pos variable
return pos;
}
void archiveWrite(int a, ArchivePos pos, const char* filename, const char* data, int size)
{
// Is this for the end of the file
if(pos.end)
{
// Write the filename to the end of the file
uint32_t filename_size = strlen(filename);
stringWrite(archives[a], (char*)&filename_size, sizeof(filename_size));
stringWrite(archives[a], filename, filename_size);
// Write the data to the end of the file
uint32_t usize = size;
stringWrite(archives[a], (char*)&usize, sizeof(usize));
stringWrite(archives[a], data, size);
}
else
{
// Setup a variable the substring
int substr_pos;
// Is the size too large for substr
if(pos.pos+size >= archives[a].size())
{
// Set the substr pos to the archives size
substr_pos = archives[a].size();
}
else
{
// Set the substr pos to the write bytes and size
substr_pos = pos.pos + size;
}
// Get the first part and the last part of the string
std::string start = archives[a].substr(0, pos.pos-sizeof(uint32_t));
std::string end = archives[a].substr(substr_pos);
// Write the data to the end of the start sring
stringWrite(start, (char*)&size, sizeof(size));
stringWrite(start, data, size);
// Add the start and end to the archive
archives[a] = start + end;
}
}
void archiveRead(int a, ArchivePos pos, char* data)
{
// Get the data from the position
int ipos = pos.pos;
stringRead(archives[a], &ipos, data, pos.size);
}
void archive_init()
{
// Load the archive
archive = archiveLoad("resources.bin", true);
// Was there an error
if(archive == -1)
{
// Load a fresh archive
archive = archiveGen("", 0, true);
}
}

23
archive.h Normal file
View File

@ -0,0 +1,23 @@
#include <cstdint>
extern int archive;
struct ArchivePos
{
bool end;
bool found;
uint32_t size;
uint32_t pos;
};
int archiveGen(const char* data, int size, bool compression=false);
int archiveLoad(const char* dir, bool compression=false);
bool archiveSave(int a, const char* dir, bool compression=false);
const char* archiveGetData(int a, int &size, bool compression=false);
void archiveFree(int a);
ArchivePos archiveGetEnd();
ArchivePos archiveGetPos(int a, const char* dir);
void archiveWrite(int a, ArchivePos pos, const char* filename, const char* data, int size);
void archiveRead(int a, ArchivePos pos, char* data);
void archive_init();

BIN
archive.o Normal file

Binary file not shown.

35
blockracer.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "mainloop.h"
#include "graphics.h"
#include "archive.h"
#include "player.h"
#include "clouds.h"
#include "world.h"
#include "input.h"
#include "text.h"
int main(int argc, char *argv[])
{
// Initialise the mainloop
mainloopInit();
// Register some actions
mainloopRegAction(player_actions, 10, 0);
mainloopRegAction(input_check, 10, 0);
mainloopRegAction(clouds_move, 10, 0);
// Initialise the archive manager
archive_init();
// Initialse everything
graphics_init(argc, argv);
clouds_init();
player_init();
input_init();
world_init();
// Start the mainloop
mainloopDoMainloop();
// Return 0
return 0;
}

BIN
blockracer.o Normal file

Binary file not shown.

547
blocks.cpp Normal file
View File

@ -0,0 +1,547 @@
#include <GL/glut.h>
#include <vector>
#include <math.h>
#include "PerlinNoise.hpp"
#include "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();
}

54
blocks.h Normal file
View File

@ -0,0 +1,54 @@
#include <cstdint>
#define BLOCK_AIR 0
#define BLOCK_STONE 1
#define BLOCK_GRASS 2
#define BLOCK_DIRT 3
#define BLOCK_GRAVEL 4
#define BLOCK_ASPHELT 5
#define BLOCK_BARRIER 6
#define BLOCK_GRASS_PLANT 7
#define BLOCK_WATER 8
#define BLOCK_SAND 9
#define BTYPE_BLOCK 0
#define BTYPE_RAMP 1
#define BTYPE_PLANT 2
#define BTYPE_FLUID 3
#define DIRECTION_N 0
#define DIRECTION_E 1
#define DIRECTION_S 2
#define DIRECTION_W 3
struct Block
{
uint8_t id=0;
uint8_t type=0;
uint8_t direction=0;
};
struct BlockFaceMap
{
bool t, b, n, e, s, w;
};
struct BlockTextures
{
int t, b, n, e, s, w;
};
struct BlockSettings
{
bool transparent;
BlockTextures tex;
};
void blocks_init();
Block make_block(uint8_t id, uint8_t type=0, uint8_t direction=0);
void render_block(Block block, int x, int y, int z, BlockFaceMap fm);
void unbind_block_texture();
void bind_block_texture();
BlockSettings blockGetSettings(int id);
void render_block_face_here(Block block);
double get_fluid_motion(int x, int z);

BIN
blocks.o Normal file

Binary file not shown.

129
clouds.cpp Normal file
View File

@ -0,0 +1,129 @@
#include <GL/glut.h>
#include <math.h>
#include <iostream>
#include "PerlinNoise.hpp"
#include "textures.h"
#include "mainloop.h"
#include "random.h"
#include "math.h"
int cloud_tex;
char* cloud_data;
int cloud_dimentions[2] = {100, 100};
double cloud_fade_distance = 25;
double cloud_frequency = 32;
double cloud_time = 0;
double frequency = 10;
const siv::PerlinNoise perlin;
void clouds_init()
{
// Setup the cloud data
cloud_data = new char[cloud_dimentions[0]*cloud_dimentions[1]*4];
// Fill the clouds with data
for(int x=0;x<cloud_dimentions[0];x++) {
for(int y=0;y<cloud_dimentions[1];y++)
{
// Get the id
int id = (x*cloud_dimentions[1]+y)*4;
// Set some noise
cloud_data[id+0] = 255;
cloud_data[id+1] = 255;
cloud_data[id+2] = 255;
}
}
}
void clouds_move(int *args)
{
// Make this happen again
mainloopRegAction(clouds_move, 10, 0);
// Add to the time
cloud_time += 1e-3;
}
void clouds_render()
{
// Fill the clouds with data
for(int x=0;x<cloud_dimentions[0];x++) {
for(int y=0;y<cloud_dimentions[1];y++)
{
// Get the id
int id = (x*cloud_dimentions[1]+y)*4;
// Get the distance between pixels
double distance = sqrt(
squarei(x - cloud_dimentions[0]/2) +
squarei(y - cloud_dimentions[1]/2)
);
// Is the distance less than 50
if(distance < cloud_dimentions[0]/2.0)
{
// Make some noise
double n = perlin.octaveNoise0_1(
x/cloud_frequency,
y/cloud_frequency,
cloud_time, 10);
char noise;
if(n < 0) noise = 0;
else if(n > 1) noise = 255;
else noise = n*255;
// Is the distance greater than 10
if(distance > cloud_dimentions[0]/2.0-cloud_fade_distance)
{
// Set distance opacity
cloud_data[id+3] = 255-
(distance-(cloud_dimentions[0]/2.0-cloud_fade_distance))/cloud_fade_distance*255;
}
else
{
// Set normal opacity
cloud_data[id+3] = 255;
}
// Set some noise
cloud_data[id+0] = noise;
cloud_data[id+1] = noise;
cloud_data[id+2] = noise;
}
else
{
// Set the opacity to zero
cloud_data[id+3] = 0;
}
}
}
// Load the clouds texture as linear
cloud_tex = loadPixels(cloud_data, cloud_dimentions[0], cloud_dimentions[1], 'L', false);
// Start rendering the clouds
glBegin(GL_QUADS);
// Draw the clouds above the player
glTexCoord2i(0,0); glVertex3d(-10, 1,-10);
glTexCoord2i(1,0); glVertex3d( 10, 1,-10);
glTexCoord2i(1,1); glVertex3d( 10, 1, 10);
glTexCoord2i(0,1); glVertex3d(-10, 1, 10);
// Stop rendering the clouds
glEnd();
// Unbind the texture
glBindTexture(GL_TEXTURE_2D, cloud_tex);
// Clear the depth
glClear(GL_DEPTH_BUFFER_BIT);
}

3
clouds.h Normal file
View File

@ -0,0 +1,3 @@
void clouds_init();
void clouds_move(int *args);
void clouds_render();

BIN
clouds.o Normal file

Binary file not shown.

126
compression.cpp Normal file
View File

@ -0,0 +1,126 @@
#include <string>
#include <stdexcept>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstring>
#include <zlib.h>
char* compress_string(const char* cstr, uint64_t size, uint64_t *size_out)
{
// Set the compression level
int compressionlevel = Z_BEST_COMPRESSION;
// Setup the string
std::string str(cstr, size);
z_stream zs; // z_stream is zlib's control structure
memset(&zs, 0, sizeof(zs));
if (deflateInit(&zs, compressionlevel) != Z_OK)
throw(std::runtime_error("deflateInit failed while compressing."));
zs.next_in = (Bytef*)str.data();
zs.avail_in = str.size(); // set the z_stream's input
int ret;
char outbuffer[32768];
std::string outstring;
// retrieve the compressed bytes blockwise
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = sizeof(outbuffer);
ret = deflate(&zs, Z_FINISH);
if (outstring.size() < zs.total_out) {
// append the block to the output string
outstring.append(outbuffer,
zs.total_out - outstring.size());
}
} while (ret == Z_OK);
deflateEnd(&zs);
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
std::ostringstream oss;
oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
throw(std::runtime_error(oss.str()));
}
// Get the size
*size_out = outstring.size();
// Get the char array to return
char* out = new char[*size_out];
// Loop over the outstring varible
for(int i=0;i<*size_out;i++)
{
// Add the string item to the char array
out[i] = outstring[i];
}
// Return out
return out;
}
char* decompress_string(const char* cstr, uint64_t size, uint64_t *size_out)
{
// Setup the string
std::string str(cstr, size);
z_stream zs; // z_stream is zlib's control structure
memset(&zs, 0, sizeof(zs));
if (inflateInit(&zs) != Z_OK)
throw(std::runtime_error("inflateInit failed while decompressing."));
zs.next_in = (Bytef*)str.data();
zs.avail_in = str.size();
int ret;
char outbuffer[32768];
std::string outstring;
// get the decompressed bytes blockwise using repeated calls to inflate
do {
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = sizeof(outbuffer);
ret = inflate(&zs, 0);
if (outstring.size() < zs.total_out) {
outstring.append(outbuffer,
zs.total_out - outstring.size());
}
} while (ret == Z_OK);
inflateEnd(&zs);
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
std::ostringstream oss;
oss << "Exception during zlib decompression: (" << ret << ") "
<< zs.msg;
throw(std::runtime_error(oss.str()));
}
// Get the size
*size_out = outstring.size();
// Get the char array to return
char* out = new char[*size_out];
// Loop over the outstring varible
for(int i=0;i<*size_out;i++)
{
// Add the string item to the char array
out[i] = outstring[i];
}
// Return out
return out;
}

2
compression.h Normal file
View File

@ -0,0 +1,2 @@
char* compress_string(const char* cstr, uint64_t size, uint64_t *size_out);
char* decompress_string(const char* cstr, uint64_t size, uint64_t *size_out);

BIN
compression.o Normal file

Binary file not shown.

599
gamepad.c Normal file
View File

@ -0,0 +1,599 @@
/**
* Gamepad Input Library
* Sean Middleditch
* Copyright (C) 2010 Sean Middleditch
* LICENSE: MIT/X
*/
#include <math.h>
#include <string.h>
#include <errno.h>
#include <malloc.h>
#define GAMEPAD_EXPORT 1
#include "gamepad.h"
/* Platform-specific includes */
#if defined(_WIN32)
# define WIN32_LEAN_AND_MEAN 1
# undef UNICODE
# include "windows.h"
# include "xinput.h"
# pragma comment(lib, "xinput.lib")
#elif defined(__linux__)
# include <linux/joystick.h>
# include <stdio.h>
# include <fcntl.h>
# include <unistd.h>
# include <libudev.h>
#else
# error "Unknown platform in gamepad.c"
#endif
#define BUTTON_TO_FLAG(b) (1 << (b))
/* Axis information */
typedef struct GAMEPAD_AXIS GAMEPAD_AXIS;
struct GAMEPAD_AXIS {
int x, y;
float nx, ny;
float length;
float angle;
GAMEPAD_STICKDIR dirLast, dirCurrent;
};
/* Trigger value information */
typedef struct GAMEPAD_TRIGINFO GAMEPAD_TRIGINFO;
struct GAMEPAD_TRIGINFO {
int value;
float length;
GAMEPAD_BOOL pressedLast, pressedCurrent;
};
/* Structure for state of a particular gamepad */
typedef struct GAMEPAD_STATE GAMEPAD_STATE;
struct GAMEPAD_STATE {
GAMEPAD_AXIS stick[STICK_COUNT];
GAMEPAD_TRIGINFO trigger[TRIGGER_COUNT];
int bLast, bCurrent, flags;
#if defined(__linux__)
char* device;
int fd;
int effect;
#endif
};
/* State of the four gamepads */
static GAMEPAD_STATE STATE[4];
/* Note whether a gamepad is currently connected */
#define FLAG_CONNECTED (1<<0)
#define FLAG_RUMBLE (1<<1)
/* Prototypes for utility functions */
static void GamepadResetState (GAMEPAD_DEVICE gamepad);
static void GamepadUpdateCommon (void);
static void GamepadUpdateDevice (GAMEPAD_DEVICE gamepad);
static void GamepadUpdateStick (GAMEPAD_AXIS* axis, float deadzone);
static void GamepadUpdateTrigger (GAMEPAD_TRIGINFO* trig);
/* Various values of PI */
#define PI_1_4 0.78539816339744f
#define PI_1_2 1.57079632679489f
#define PI_3_4 2.35619449019234f
#define PI 3.14159265358979f
/* Platform-specific implementation code */
#if defined(_WIN32)
void GamepadInit(void) {
int i;
for (i = 0; i != GAMEPAD_COUNT; ++i) {
STATE[i].flags = 0;
}
}
void GamepadUpdate(void) {
GamepadUpdateCommon();
}
static void GamepadUpdateDevice(GAMEPAD_DEVICE gamepad) {
XINPUT_STATE xs;
if (XInputGetState(gamepad, &xs) == 0) {
/* reset if the device was not already connected */
if ((STATE[gamepad].flags & FLAG_CONNECTED) == 0) {
GamepadResetState(gamepad);
}
/* mark that we are connected w/ rumble support */
STATE[gamepad].flags |= FLAG_CONNECTED|FLAG_RUMBLE;
/* update state */
STATE[gamepad].bCurrent = xs.Gamepad.wButtons;
STATE[gamepad].trigger[TRIGGER_LEFT].value = xs.Gamepad.bLeftTrigger;
STATE[gamepad].trigger[TRIGGER_RIGHT].value = xs.Gamepad.bRightTrigger;
STATE[gamepad].stick[STICK_LEFT].x = xs.Gamepad.sThumbLX;
STATE[gamepad].stick[STICK_LEFT].y = xs.Gamepad.sThumbLY;
STATE[gamepad].stick[STICK_RIGHT].x = xs.Gamepad.sThumbRX;
STATE[gamepad].stick[STICK_RIGHT].y = xs.Gamepad.sThumbRY;
} else {
/* disconnected */
STATE[gamepad].flags &= ~FLAG_CONNECTED;
}
}
void GamepadShutdown(void) {
/* no Win32 shutdown required */
}
void GamepadSetRumble(GAMEPAD_DEVICE gamepad, float left, float right) {
if ((STATE[gamepad].flags & FLAG_RUMBLE) != 0) {
XINPUT_VIBRATION vib;
ZeroMemory(&vib, sizeof(vib));
vib.wLeftMotorSpeed = (WORD)(left * 65535);
vib.wRightMotorSpeed = (WORD)(right * 65535);
XInputSetState(gamepad, &vib);
}
}
#elif defined(__linux__)
/* UDev handles */
static struct udev* UDEV = NULL;
static struct udev_monitor* MON = NULL;
static void GamepadAddDevice(const char* devPath);
static void GamepadRemoveDevice(const char* devPath);
/* Helper to add a new device */
static void GamepadAddDevice(const char* devPath) {
int i;
/* try to find a free controller */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if ((STATE[i].flags & FLAG_CONNECTED) == 0) {
break;
}
}
if (i == GAMEPAD_COUNT) {
return;
}
/* copy the device path */
STATE[i].device = strdup(devPath);
if (STATE[i].device == NULL) {
return;
}
/* reset device state */
GamepadResetState(i);
/* attempt to open the device in read-write mode, which we need fo rumble */
STATE[i].fd = open(STATE[i].device, O_RDWR|O_NONBLOCK);
if (STATE[i].fd != -1) {
STATE[i].flags = FLAG_CONNECTED|FLAG_RUMBLE;
return;
}
/* attempt to open in read-only mode if access was denied */
if (errno == EACCES) {
STATE[i].fd = open(STATE[i].device, O_RDONLY|O_NONBLOCK);
if (STATE[i].fd != -1) {
STATE[i].flags = FLAG_CONNECTED;
return;
}
}
/* could not open the device at all */
free(STATE[i].device);
STATE[i].device = NULL;
}
/* Helper to remove a device */
static void GamepadRemoveDevice(const char* devPath) {
int i;
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if (STATE[i].device != NULL && strcmp(STATE[i].device, devPath) == 0) {
if (STATE[i].fd != -1) {
close(STATE[i].fd);
STATE[i].fd = -1;
}
free(STATE[i].device);
STATE[i].device = 0;
STATE[i].flags = 0;
break;
}
}
}
void GamepadInit(void) {
struct udev_list_entry* devices;
struct udev_list_entry* item;
struct udev_enumerate* enu;
int i;
/* initialize connection state */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
STATE[i].flags = 0;
STATE[i].fd = STATE[i].effect = -1;
}
/* open the udev handle */
UDEV = udev_new();
if (UDEV == NULL) {
/* FIXME: flag error? */
return;
}
/* open monitoring device (safe to fail) */
MON = udev_monitor_new_from_netlink(UDEV, "udev");
/* FIXME: flag error if hot-plugging can't be supported? */
if (MON != NULL) {
udev_monitor_enable_receiving(MON);
udev_monitor_filter_add_match_subsystem_devtype(MON, "input", NULL);
}
/* enumerate joypad devices */
enu = udev_enumerate_new(UDEV);
udev_enumerate_add_match_subsystem(enu, "input");
udev_enumerate_scan_devices(enu);
devices = udev_enumerate_get_list_entry(enu);
udev_list_entry_foreach(item, devices) {
const char* name;
const char* sysPath;
const char* devPath;
struct udev_device* dev;
name = udev_list_entry_get_name(item);
dev = udev_device_new_from_syspath(UDEV, name);
sysPath = udev_device_get_syspath(dev);
devPath = udev_device_get_devnode(dev);
if (sysPath != NULL && devPath != NULL && strstr(sysPath, "/js") != 0) {
GamepadAddDevice(devPath);
}
udev_device_unref(dev);
}
/* cleanup */
udev_enumerate_unref(enu);
}
void GamepadUpdate(void) {
if (MON != NULL) {
fd_set r;
struct timeval tv;
int fd = udev_monitor_get_fd(MON);
/* set up a poll on the udev device */
FD_ZERO(&r);
FD_SET(fd, &r);
tv.tv_sec = 0;
tv.tv_usec = 0;
select(fd + 1, &r, 0, 0, &tv);
/* test if we have a device change */
if (FD_ISSET(fd, &r)) {
struct udev_device* dev = udev_monitor_receive_device(MON);
if (dev) {
const char* devNode = udev_device_get_devnode(dev);
const char* sysPath = udev_device_get_syspath(dev);
const char* action = udev_device_get_action(dev);
sysPath = udev_device_get_syspath(dev);
action = udev_device_get_action(dev);
if (strstr(sysPath, "/js") != 0) {
if (strcmp(action, "remove") == 0) {
GamepadRemoveDevice(devNode);
} else if (strcmp(action, "add") == 0) {
GamepadAddDevice(devNode);
}
}
udev_device_unref(dev);
}
}
}
GamepadUpdateCommon();
}
static void GamepadUpdateDevice(GAMEPAD_DEVICE gamepad) {
if (STATE[gamepad].flags & FLAG_CONNECTED) {
struct js_event je;
while (read(STATE[gamepad].fd, &je, sizeof(je)) > 0) {
int button;
switch (je.type) {
case JS_EVENT_BUTTON:
/* determine which button the event is for */
switch (je.number) {
case 0: button = BUTTON_A; break;
case 1: button = BUTTON_B; break;
case 2: button = BUTTON_X; break;
case 3: button = BUTTON_Y; break;
case 4: button = BUTTON_LEFT_SHOULDER; break;
case 5: button = BUTTON_RIGHT_SHOULDER; break;
case 6: button = BUTTON_BACK; break;
case 7: button = BUTTON_START; break;
case 8: button = 0; break; /* XBOX button */
case 9: button = BUTTON_LEFT_THUMB; break;
case 10: button = BUTTON_RIGHT_THUMB; break;
default: button = 0; break;
}
/* set or unset the button */
if (je.value) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(button);
} else {
STATE[gamepad].bCurrent ^= BUTTON_TO_FLAG(button);
}
break;
case JS_EVENT_AXIS:
/* normalize and store the axis */
switch (je.number) {
case 0: STATE[gamepad].stick[STICK_LEFT].x = je.value; break;
case 1: STATE[gamepad].stick[STICK_LEFT].y = -je.value; break;
case 2: STATE[gamepad].trigger[TRIGGER_LEFT].value = (je.value + 32768) >> 8; break;
case 3: STATE[gamepad].stick[STICK_RIGHT].x = je.value; break;
case 4: STATE[gamepad].stick[STICK_RIGHT].y = -je.value; break;
case 5: STATE[gamepad].trigger[TRIGGER_RIGHT].value = (je.value + 32768) >> 8; break;
case 6:
if (je.value == -32767) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(BUTTON_DPAD_LEFT);
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_RIGHT);
} else if (je.value == 32767) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(BUTTON_DPAD_RIGHT);
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_LEFT);
} else {
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_LEFT) & ~BUTTON_TO_FLAG(BUTTON_DPAD_RIGHT);
}
break;
case 7:
if (je.value == -32767) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(BUTTON_DPAD_UP);
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_DOWN);
} else if (je.value == 32767) {
STATE[gamepad].bCurrent |= BUTTON_TO_FLAG(BUTTON_DPAD_DOWN);
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_UP);
} else {
STATE[gamepad].bCurrent &= ~BUTTON_TO_FLAG(BUTTON_DPAD_UP) & ~BUTTON_TO_FLAG(BUTTON_DPAD_DOWN);
}
break;
default: break;
}
break;
default:
break;
}
}
}
}
void GamepadShutdown(void) {
int i;
/* cleanup udev */
udev_monitor_unref(MON);
udev_unref(UDEV);
/* cleanup devices */
for (i = 0; i != GAMEPAD_COUNT; ++i) {
if (STATE[i].device != NULL) {
free(STATE[i].device);
}
if (STATE[i].fd != -1) {
close(STATE[i].fd);
}
}
}
void GamepadSetRumble(GAMEPAD_DEVICE gamepad, float left, float right) {
if (STATE[gamepad].fd != -1) {
struct input_event play;
/* delete any existing effect */
if (STATE[gamepad].effect != -1) {
/* stop the effect */
play.type = EV_FF;
play.code = STATE[gamepad].effect;
play.value = 0;
write(STATE[gamepad].fd, (const void*)&play, sizeof(play));
/* delete the effect */
ioctl(STATE[gamepad].fd, EVIOCRMFF, STATE[gamepad].effect);
}
/* if rumble parameters are non-zero, start the new effect */
if (left != 0.f || right != 0.f) {
struct ff_effect ff;
/* define an effect for this rumble setting */
ff.type = FF_RUMBLE;
ff.id = -1;
ff.u.rumble.strong_magnitude = (unsigned short)(left * 65535);
ff.u.rumble.weak_magnitude = (unsigned short)(right * 65535);
ff.replay.length = 5;
ff.replay.delay = 0;
/* upload the effect */
if (ioctl(STATE[gamepad].fd, EVIOCSFF, &ff) != -1) {
STATE[gamepad].effect = ff.id;
}
/* play the effect */
play.type = EV_FF;
play.code = STATE[gamepad].effect;
play.value = 1;
write(STATE[gamepad].fd, (const void*)&play, sizeof(play));
}
}
}
#else /* !defined(_WIN32) && !defined(__linux__) */
# error "Unknown platform in gamepad.c"
#endif /* end of platform implementations */
GAMEPAD_BOOL GamepadIsConnected(GAMEPAD_DEVICE device) {
return (STATE[device].flags & FLAG_CONNECTED) != 0 ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadButtonDown(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button) {
return (STATE[device].bCurrent & BUTTON_TO_FLAG(button)) != 0 ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadButtonTriggered(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button) {
return ((STATE[device].bLast & BUTTON_TO_FLAG(button)) == 0 &&
(STATE[device].bCurrent & BUTTON_TO_FLAG(button)) != 0) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadButtonReleased(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button) {
return ((STATE[device].bCurrent & BUTTON_TO_FLAG(button)) == 0 &&
(STATE[device].bLast & BUTTON_TO_FLAG(button)) != 0) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
int GamepadTriggerValue(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return STATE[device].trigger[trigger].value;
}
float GamepadTriggerLength(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return STATE[device].trigger[trigger].length;
}
GAMEPAD_BOOL GamepadTriggerDown(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return STATE[device].trigger[trigger].pressedCurrent;
}
GAMEPAD_BOOL GamepadTriggerTriggered(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return (STATE[device].trigger[trigger].pressedCurrent &&
!STATE[device].trigger[trigger].pressedLast) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
GAMEPAD_BOOL GamepadTriggerReleased(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger) {
return (!STATE[device].trigger[trigger].pressedCurrent &&
STATE[device].trigger[trigger].pressedLast) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
void GamepadStickXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, int *outX, int *outY) {
*outX = STATE[device].stick[stick].x;
*outY = STATE[device].stick[stick].y;
}
float GamepadStickLength(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
return STATE[device].stick[stick].length;
}
void GamepadStickNormXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, float *outX, float *outY) {
*outX = STATE[device].stick[stick].nx;
*outY = STATE[device].stick[stick].ny;
}
float GamepadStickAngle(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
return STATE[device].stick[stick].angle;
}
GAMEPAD_STICKDIR GamepadStickDir(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
return STATE[device].stick[stick].dirCurrent;
}
GAMEPAD_BOOL GamepadStickDirTriggered(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, GAMEPAD_STICKDIR dir) {
return (STATE[device].stick[stick].dirCurrent == dir &&
STATE[device].stick[stick].dirCurrent != STATE[device].stick[stick].dirLast) ? GAMEPAD_TRUE : GAMEPAD_FALSE;
}
/* initialize common gamepad state */
static void GamepadResetState(GAMEPAD_DEVICE gamepad) {
memset(STATE[gamepad].stick, 0, sizeof(STATE[gamepad].stick));
memset(STATE[gamepad].trigger, 0, sizeof(STATE[gamepad].trigger));
STATE[gamepad].bLast = STATE[gamepad].bCurrent = 0;
}
/* Update individual sticks */
static void GamepadUpdateCommon(void) {
int i;
for (i = 0; i != GAMEPAD_COUNT; ++i) {
/* store previous button state */
STATE[i].bLast = STATE[i].bCurrent;
/* per-platform update routines */
GamepadUpdateDevice((GAMEPAD_DEVICE)i);
/* calculate refined stick and trigger values */
if ((STATE[i].flags & FLAG_CONNECTED) != 0) {
GamepadUpdateStick(&STATE[i].stick[STICK_LEFT], GAMEPAD_DEADZONE_LEFT_STICK);
GamepadUpdateStick(&STATE[i].stick[STICK_RIGHT], GAMEPAD_DEADZONE_RIGHT_STICK);
GamepadUpdateTrigger(&STATE[i].trigger[TRIGGER_LEFT]);
GamepadUpdateTrigger(&STATE[i].trigger[TRIGGER_RIGHT]);
}
}
}
/* Update stick info */
static void GamepadUpdateStick(GAMEPAD_AXIS* axis, float deadzone) {
// determine magnitude of stick
axis->length = sqrtf((float)(axis->x*axis->x) + (float)(axis->y*axis->y));
if (axis->length > deadzone) {
// clamp length to maximum value
if (axis->length > 32767.0f) {
axis->length = 32767.0f;
}
// normalized X and Y values
axis->nx = axis->x / axis->length;
axis->ny = axis->y / axis->length;
// adjust length for deadzone and find normalized length
axis->length -= deadzone;
axis->length /= (32767.0f - deadzone);
// find angle of stick in radians
axis->angle = atan2f((float)axis->y, (float)axis->x);
} else {
axis->x = axis->y = 0;
axis->nx = axis->ny = 0.0f;
axis->length = axis->angle = 0.0f;
}
/* update the stick direction */
axis->dirLast = axis->dirCurrent;
axis->dirCurrent = STICKDIR_CENTER;
/* check direction to see if it's non-centered */
if (axis->length != 0.f) {
if (axis->angle >= PI_1_4 && axis->angle < PI_3_4) {
axis->dirCurrent = STICKDIR_UP;
} else if (axis->angle >= -PI_3_4 && axis->angle < -PI_1_4) {
axis->dirCurrent = STICKDIR_DOWN;
} else if (axis->angle >= PI_3_4 || axis->angle < -PI_3_4) {
axis->dirCurrent = STICKDIR_LEFT;
} else /* if (axis->angle < PI_1_4 && axis->angle >= -PI_1_4) */ {
axis->dirCurrent = STICKDIR_RIGHT;
}
}
}
/* Update trigger info */
static void GamepadUpdateTrigger(GAMEPAD_TRIGINFO* trig) {
trig->pressedLast = trig->pressedCurrent;
if (trig->value > GAMEPAD_DEADZONE_TRIGGER) {
trig->length = ((trig->value - GAMEPAD_DEADZONE_TRIGGER) / (255.0f - GAMEPAD_DEADZONE_TRIGGER));
trig->pressedCurrent = GAMEPAD_TRUE;
} else {
trig->value = 0;
trig->length = 0.0f;
trig->pressedCurrent = GAMEPAD_FALSE;
}
}

323
gamepad.h Normal file
View File

@ -0,0 +1,323 @@
/**
* Gamepad Input Library
* Sean Middleditch <sean@middleditch.us>
* Copyright (C) 2010,2011 Sean Middleditch
* LICENSE: MIT/X
*/
#if !defined(GAMEPAD_H)
#define GAMEPAD_H 1
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(GAMEPAD_STATIC_LIB)
# define GAMEPAD_API
#else
# if defined(_WIN32)
# if defined(GAMEPAD_EXPORT)
# define GAMEPAD_API __declspec(dllexport)
# else
# define GAMEPAD_API __declspec(dllimport)
# endif
# elif defined(__GNUC__) && defined(GAMEPAD_EXPORT)
# define GAMEPAD_API __attribute__((visibility("default")))
# else
# define GAMEPAD_API extern
# endif
#endif
/**
* Enumeration of the possible devices.
*
* Only four devices are supported as this is the limit of Windows.
*/
enum GAMEPAD_DEVICE {
GAMEPAD_0 = 0, /**< First gamepad */
GAMEPAD_1 = 1, /**< Second gamepad */
GAMEPAD_2 = 2, /**< Third gamepad */
GAMEPAD_3 = 3, /**< Fourth gamepad */
GAMEPAD_COUNT /**< Maximum number of supported gamepads */
};
/**
* Enumeration of the possible buttons.
*/
enum GAMEPAD_BUTTON {
BUTTON_DPAD_UP = 0, /**< UP on the direction pad */
BUTTON_DPAD_DOWN = 1, /**< DOWN on the direction pad */
BUTTON_DPAD_LEFT = 2, /**< LEFT on the direction pad */
BUTTON_DPAD_RIGHT = 3, /**< RIGHT on the direction pad */
BUTTON_START = 4, /**< START button */
BUTTON_BACK = 5, /**< BACK button */
BUTTON_LEFT_THUMB = 6, /**< Left analog stick button */
BUTTON_RIGHT_THUMB = 7, /**< Right analog stick button */
BUTTON_LEFT_SHOULDER = 8, /**< Left bumper button */
BUTTON_RIGHT_SHOULDER = 9, /**< Right bumper button */
BUTTON_A = 12, /**< A button */
BUTTON_B = 13, /**< B button */
BUTTON_X = 14, /**< X button */
BUTTON_Y = 15, /**< Y button */
BUTTON_COUNT /**< Maximum number of supported buttons */
};
/**
* Enumeration of the possible pressure/trigger buttons.
*/
enum GAMEPAD_TRIGGER {
TRIGGER_LEFT = 0, /**< Left trigger */
TRIGGER_RIGHT = 1, /**< Right trigger */
TRIGGER_COUNT /**< Number of triggers */
};
/**
* Enumeration of the analog sticks.
*/
enum GAMEPAD_STICK {
STICK_LEFT = 0, /**< Left stick */
STICK_RIGHT = 1, /**< Right stick */
STICK_COUNT /**< Number of analog sticks */
};
/**
* Enumeration of main stick directions.
*
* This is used for some of the convenience routines in the library.
*/
enum GAMEPAD_STICKDIR {
STICKDIR_CENTER = 0, /**< CENTER, no direction */
STICKDIR_UP = 1, /**< UP direction */
STICKDIR_DOWN = 2, /**< DOWN direction */
STICKDIR_LEFT = 3, /**< LEFT direction */
STICKDIR_RIGHT = 4, /**< RIGHT direction */
STICKDIR_COUNT
};
/**
* Enumeration for true/false values
*/
enum GAMEPAD_BOOL {
GAMEPAD_FALSE = 0, /**< FALSE value for boolean parameters */
GAMEPAD_TRUE = 1 /**< TRUE value for boolean parameters */
};
typedef enum GAMEPAD_DEVICE GAMEPAD_DEVICE;
typedef enum GAMEPAD_BUTTON GAMEPAD_BUTTON;
typedef enum GAMEPAD_TRIGGER GAMEPAD_TRIGGER;
typedef enum GAMEPAD_STICK GAMEPAD_STICK;
typedef enum GAMEPAD_STICKDIR GAMEPAD_STICKDIR;
typedef enum GAMEPAD_BOOL GAMEPAD_BOOL;
#define GAMEPAD_DEADZONE_LEFT_STICK 7849 /**< Suggested deadzone magnitude for left analog stick */
#define GAMEPAD_DEADZONE_RIGHT_STICK 8689 /**< Suggested deadzone magnitude for right analog stick */
#define GAMEPAD_DEADZONE_TRIGGER 30 /**< Suggested deadzone for triggers */
/**
* Initialize the library.
*
* This is critical on non-Windows platforms.
*/
GAMEPAD_API void GamepadInit(void);
/**
* Shutdown the library.
*
* This will release resources allocated by the library internally.
*
* This should be called after forking as well.
*/
GAMEPAD_API void GamepadShutdown(void);
/**
* Updates the state of the gamepads.
*
* This must be called (at least) once per game loop.
*/
GAMEPAD_API void GamepadUpdate(void);
/**
* Test if a particular gamepad is connected.
*
* \param device The device to check.
* \returns GAMEPAD_TRUE if the device is connected, GAMEPAD_FALSE if it is not.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadIsConnected(GAMEPAD_DEVICE device);
/**
* Test if a particular button is being pressed.
*
* \param device The device to check.
* \param button The button to check.
* \returns GAMEPAD_TRUE if the button is down, GAMEPAD_FALSE if it is not.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadButtonDown(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button);
/**
* Test if a particular button has been depressed since the previous call to GamepadUpdate.
*
* \param device The device to check.
* \param button The button to check.
* \returns GAMEPAD_TRUE if the button has been pressed, GAMEPAD_FALSE if it is not or if it was depressed the previous frame.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadButtonTriggered(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button);
/**
* Test if a particular button has been released since the previous call to GamepadUpdate.
*
* \param device The device to check.
* \param button The button to check.
* \returns GAMEPAD_TRUE if the button has been released, GAMEPAD_FALSE if it is down or if it was not down the previous frame.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadButtonReleased(GAMEPAD_DEVICE device, GAMEPAD_BUTTON button);
/**
* Get the trigger value (depression magnitude) in its raw form.
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns Trigger depression magnitude (0 to 32767).
*/
GAMEPAD_API int GamepadTriggerValue(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Get the trigger value (depression magnitude) in normalized form.
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns Trigger depression magnitude (0 to 1).
*/
GAMEPAD_API float GamepadTriggerLength(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Test if a trigger is depressed
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns GAMEPAD_TRUE if down, GAMEPAD_FALSE otherwise.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadTriggerDown(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Test if a trigger is depressed
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns GAMEPAD_TRUE if triggered, GAMEPAD_FALSE otherwise.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadTriggerTriggered(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Test if a trigger is depressed
*
* \param device The device to check.
* \param trigger The trigger to check.
* \returns GAMEPAD_TRUE if released, GAMEPAD_FALSE otherwise.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadTriggerReleased(GAMEPAD_DEVICE device, GAMEPAD_TRIGGER trigger);
/**
* Set the rumble motors on/off.
*
* To turn off the rumble effect, set values to 0 for both motors.
*
* The left motor is the low-frequency/strong motor, and the right motor is the high-frequency/weak motor.
*
* \param device The device to update.
* \param left Left motor strengh (0 to 1).
* \param right Right motor strengh (0 to 1).
*/
GAMEPAD_API void GamepadSetRumble(GAMEPAD_DEVICE device, float left, float right);
/**
* Query the position of an analog stick as raw values.
*
* The values retrieved by this function represent the magnitude of the analog
* stick in each direction. Note that it shouldn't be possible to get full
* magnitude in one direction unless the other direction has a magnitude of
* zero, as the stick has a circular movement range.
*
* \param device The device to check.
* \param stick The stick to check.
* \param outX Pointer to integer to store the X magnitude in (-32767 to 32767).
* \param outX Pointer to integer to store the Y magnitude in (-32767 to 32767).
*/
GAMEPAD_API void GamepadStickXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, int* outX, int* outY);
/**
* Query the position of an analog stick as normalized values.
*
* The values retrieved by this function represent the magnitude of the analog
* stick in each direction. Note that it shouldn't be possible to get full
* magnitude in one direction unless the other direction has a magnitude of
* zero, as the stick has a circular movement range.
*
* \param device The device to check.
* \param stick The stick to check.
* \param outX Pointer to float to store the X magnitude in (-1 to 1).
* \param outX Pointer to float to store the Y magnitude in (-1 to 1).
*/
GAMEPAD_API void GamepadStickNormXY(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, float* outX, float* outY);
/**
* Query the magnitude of an analog stick.
*
* This returns the normalized value of the magnitude of the stick. That is,
* if the stick is pushed all the way in any direction, it returns 1.0.
*
* \param device The device to check.
* \param stick The stick to check.
* \returns The magnitude of the stick (0 to 1).
*/
GAMEPAD_API float GamepadStickLength(GAMEPAD_DEVICE device, GAMEPAD_STICK stick);
/**
* Query the direction of a stick (in radians).
*
* This returns the direction of the stick. This value is in radians, not
* degrees. Zero is to the right, and the angle increases in a
* counter-clockwise direction.
*
* \param device The device to check.
* \param stick The stick to check.
* \returns The angle of the stick (0 to 2*PI).
*/
GAMEPAD_API float GamepadStickAngle(GAMEPAD_DEVICE device, GAMEPAD_STICK stick);
/**
* Get the direction the stick is pushed in (if any).
*
* This is a useful utility function for when the stick should be treated as a simple
* directional pad, such as for menu UIs.
*
* \param device The device to check.
* \param stick The trigger to check.
* \returns The stick's current direction.
*/
GAMEPAD_API GAMEPAD_STICKDIR GamepadStickDir(GAMEPAD_DEVICE device, GAMEPAD_STICK stick);
/**
* Test whether a stick has been pressed in a particular direction since the last update.
*
* This only returns true if the stick was centered last frame.
*
* This is a useful utility function for when the stick should be treated as a simple
* directional pad, such as for menu UIs.
*
* \param device The device to check.
* \param stick The trigger to check.
* \param stickdir The direction to check for.
* \returns GAMEPAD_TRUE if the stick is pressed in the specified direction, GAMEPAD_FALSE otherwise.
*/
GAMEPAD_API GAMEPAD_BOOL GamepadStickDirTriggered(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, GAMEPAD_STICKDIR dir);
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif

BIN
gamepad.o Normal file

Binary file not shown.

264
graphics.cpp Normal file
View File

@ -0,0 +1,264 @@
#include <GL/glut.h>
#include <iostream>
#ifdef __linux__
#include <X11/Xlib.h>
#endif
#ifdef _WIN32
#include <Windows.h>
#endif
#include "mainloop.h"
#include "graphics.h"
#include "textures.h"
#include "player.h"
#include "clouds.h"
#include "world.h"
GLfloat aspect;
GLsizei w_dimentions[2];
int skymap_size[2];
int skymap_id;
int mspf=1000/30;
int max_mspf=1000/10;
int* sxy;
void on_early()
{
// Make the display interval between updates shorter
if(mspf > max_mspf) {
mspf -= 1;
}
}
void on_late()
{
// Increase the display update intervals
mspf += 1;
}
int* desktopResolution()
{
// Setup the data structure
int* data = new int[2]();
#ifdef _WIN32
// Get the desktop
RECT desktop;
// Get the desktop window
const HWND hDesktop = GetDesktopWindow();
// Process the size of the window
GetWindowRect(hDesktop, &desktop);
// Set these values
data[0] = desktop.bottom;
data[1] = desktop.right;
#endif
#ifdef __linux__
// Get the screen
Display* d = XOpenDisplay(NULL);
Screen* s = DefaultScreenOfDisplay(d);
// Set the varibles
data[0] = s->width;
data[1] = s->height;
#endif
// Return the data
return data;
}
void display()
{
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set perspective view
gluPerspective(100.0f, aspect, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Enable depth
glEnable(GL_DEPTH_TEST);
/*glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 10.0, 8.0);*/
// Set the viewport
glViewport(0, 0, w_dimentions[0], w_dimentions[1]);
// Load the skymap
glBindTexture(GL_TEXTURE_2D, skymap_id);
// Rotate the angle
glRotated(player_angle[1], 1, 0, 0);
glRotated(player_angle[0], 0, 1, 0);
// Set the colour
glColor4f(0.5f,0.7f,1.0f,1.0f);
// Start drawing a cube
glBegin(GL_QUADS);
// Top
glTexCoord2d(1/3.0,0); glVertex3i(-2, 1,-2);
glTexCoord2d(0/3.0,0); glVertex3i( 2, 1,-2);
glTexCoord2d(0/3.0,1); glVertex3i( 2, 1, 2);
glTexCoord2d(1/3.0,1); glVertex3i(-2, 1, 2);
// Sides
glTexCoord2d(2/3.0,0); glVertex3i( 1,-1,-1);
glTexCoord2d(1/3.0,0); glVertex3i( 1, 1,-1);
glTexCoord2d(1/3.0,1); glVertex3i(-1, 1,-1);
glTexCoord2d(2/3.0,1); glVertex3i(-1,-1,-1);
glTexCoord2d(2/3.0,0); glVertex3i( 1,-1, 1);
glTexCoord2d(1/3.0,0); glVertex3i( 1, 1, 1);
glTexCoord2d(1/3.0,1); glVertex3i(-1, 1, 1);
glTexCoord2d(2/3.0,1); glVertex3i(-1,-1, 1);
glTexCoord2d(2/3.0,0); glVertex3i(-1,-1,-1);
glTexCoord2d(1/3.0,0); glVertex3i(-1, 1,-1);
glTexCoord2d(1/3.0,1); glVertex3i(-1, 1, 1);
glTexCoord2d(2/3.0,1); glVertex3i(-1,-1, 1);
glTexCoord2d(2/3.0,0); glVertex3i( 1,-1,-1);
glTexCoord2d(1/3.0,0); glVertex3i( 1, 1,-1);
glTexCoord2d(1/3.0,1); glVertex3i( 1, 1, 1);
glTexCoord2d(2/3.0,1); glVertex3i( 1,-1, 1);
// Bottom
glTexCoord2d(3/3.0,0); glVertex3i(-2,-1,-2);
glTexCoord2d(2/3.0,0); glVertex3i( 2,-1,-2);
glTexCoord2d(2/3.0,1); glVertex3i( 2,-1, 2);
glTexCoord2d(3/3.0,1); glVertex3i(-2,-1, 2);
// Stop drawing the cubemap
glEnd();
// Clear the depth
glClear(GL_DEPTH_BUFFER_BIT);
// Render the clouds
clouds_render();
// Translate the position
glTranslated(-player_pos[0],-player_pos[1],-player_pos[2]);
// Load the worlds blocks
world_render();
glPopMatrix();
// 2D view
/*glMatrixMode (GL_PROJECTION);
glLoadIdentity();
glOrtho(-9.0, 9.0, -9.0, 9.0, 0.0, 30.0);
glLoadIdentity();*/
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glDisable(GL_DEPTH_TEST);
glLoadIdentity();
//glPopMatrix();
// Render the player
player_render();
// Swap the front and back frame buffers
glutSwapBuffers();
}
void reshape(GLsizei width, GLsizei height)
{
// Prevent division by zero
if (width < 1) width = 1;
if (height < 1) height = 1;
w_dimentions[0] = width;
w_dimentions[1] = height;
// Get the aspect
aspect = GLfloat(width) / GLfloat(height);
// Reload the identity
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the perspective
gluPerspective(100.0f, aspect, 0.1f, 100.0f);
}
void graphics_reshape()
{
reshape(w_dimentions[0], w_dimentions[1]);
}
void render_event(int *args)
{
// Repost this event
mainloopRegAction(render_event, mspf, 0);
// Post Redisplay
glutPostRedisplay();
}
void display_event(int *args)
{
// Repost this event
mainloopRegAction(display_event, 10, 0);
// Do the glut mainloop event
glutMainLoopEvent();
}
void graphics_init(int argc, char *argv[])
{
// Initialise OpenGL
glutInit(&argc, argv);
// Get the screen size
sxy = desktopResolution();
// Set the window properties
glutCreateWindow("Racing Game");
glutInitDisplayMode(GLUT_DOUBLE);
glutReshapeWindow(sxy[0], sxy[1]);
glutFullScreen();
// Display stuff
glutDisplayFunc(display);
glutReshapeFunc(reshape);
// Enable some stuff
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
// Enable blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Load the skymap
skymap_id = loadArchiveImageGL("textures/sky.rimg", 'N', skymap_size[0], skymap_size[1]);
// Make these functions happen in the future
mainloopRegAction(display_event, 10, 0);
mainloopRegAction(render_event, 1000/60, 0);
// Handle lag
mainloopOnEarly(on_early);
mainloopOnLate(on_late);
}

4
graphics.h Normal file
View File

@ -0,0 +1,4 @@
extern int* sxy;
void graphics_init(int argc, char *argv[]);
void graphics_reshape();

BIN
graphics.o Normal file

Binary file not shown.

47
input.cpp Normal file
View File

@ -0,0 +1,47 @@
#include "mainloop.h"
#include "gamepad.h"
#include "input.h"
GAMEPAD_DEVICE dev = GAMEPAD_0;
void input_init()
{
// Initialise the gamepad
GamepadInit();
}
void input_check(int *args)
{
// Make this happen again
mainloopRegAction(input_check, 10, 0);
// Is the gamepad not connected
if(!GamepadIsConnected(dev)) return;
// Check for changes
GamepadUpdate();
}
bool gpad_button_pressed(GAMEPAD_BUTTON button)
{
// Return a boolean varible
return GamepadButtonDown(dev, button);
}
double gpad_trigger_length(GAMEPAD_TRIGGER trigger)
{
// Return the trigger value
return GamepadTriggerLength(dev, trigger);
}
double gpad_stick_length(GAMEPAD_STICK stick)
{
// Return the sticks angle in radians
return GamepadStickLength(dev, stick);
}
void gpad_stick_value(GAMEPAD_STICK stick, float &x, float &y)
{
// Return the x and y of the stick
return GamepadStickNormXY(dev, stick, &x, &y);
}

8
input.h Normal file
View File

@ -0,0 +1,8 @@
#include "gamepad.h"
void input_init();
void input_check(int *args);
bool gpad_button_pressed(GAMEPAD_BUTTON);
double gpad_trigger_length(GAMEPAD_TRIGGER);
double gpad_stick_length(GAMEPAD_STICK);
void gpad_stick_value(GAMEPAD_STICK, float&, float&);

BIN
input.o Normal file

Binary file not shown.

BIN
libgamepad.so Normal file

Binary file not shown.

1
libs/mainloop-api Submodule

@ -0,0 +1 @@
Subproject commit cd81dbe0739d8b2ad124039ca4c7d54df3cf554a

BIN
mainloop.o Normal file

Binary file not shown.

30
math.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "math.h"
void zero_out_bytes(char *data, int size)
{
// Loop over the data varible
for(int i=0;i<size;i++)
{
// Fill it with zeros
data[i] = 0x0;
}
}
// Make the input positive
double positive(double n) {
if(n >= 0) return n;
if(n < 0) return -n;
}
// Efficient squaring ( pow(d, 2) )
double squared(double d) {
return d*d;
}
float squaref(float d) {
return d*d;
}
int squarei(int d) {
return d*d;
}

7
math.h Normal file
View File

@ -0,0 +1,7 @@
#define PI 3.141592653589793
void zero_out_bytes(char *data, int size);
double positive(double n);
double squared(double n);
float squaref(float n);
int squarei(int n);

BIN
math.o Normal file

Binary file not shown.

380
player.cpp Normal file
View File

@ -0,0 +1,380 @@
#include <GL/glut.h>
#include <math.h>
#include <iostream>
#include "player.h"
#include "input.h"
#include "mainloop.h"
#include "textures.h"
#include "blocks.h"
#include "world.h"
#include "math.h"
double player_power = 0;
double player_angle[2] = {0, 0};
double player_pos[3] = {10, 0, 0};
double player_max_speed = 0.001;
double fall_speed = 0;
bool break_block_pressed = false;
bool place_block_pressed = false;
int TEX_CAR;
int TEX_BOAT;
int TEX_PLANE;
int TEX_EDITOR;
int player_mode = PLAYER_BOAT;
void player_init()
{
// Load the vehicles textures
int w, h;
//TEX_CAR = loadArchiveImageGL("textures/vehicles/car_inside.rimg", 'L', w, h);
//TEX_BOAT = loadArchiveImageGL("textures/vehicles/boat_inside.rimg", 'L', w, h);
//TEX_PLANE = loadArchiveImageGL("textures/vehicles/plane_inside.rimg", 'L', w, h);
TEX_EDITOR = loadArchiveImageGL("textures/vehicles/editor_inside.rimg", 'L', w, h);
}
void player_render()
{
// Car
if(player_mode == PLAYER_CAR)
{
// Bind the texture
glBindTexture(GL_TEXTURE_2D, TEX_EDITOR);
}
// Boat
if(player_mode == PLAYER_BOAT)
{
// Bind the texture
glBindTexture(GL_TEXTURE_2D, TEX_EDITOR);
}
// Editor
if(player_mode == PLAYER_EDITOR)
{
// Bind the texture
glBindTexture(GL_TEXTURE_2D, TEX_EDITOR);
}
glColor4f(1.0f,1.0f,1.0f,1.0f);
glBegin(GL_QUADS);
glTexCoord2d(0,0); glVertex2d(-1, 1);
glTexCoord2d(1,0); glVertex2d( 1, 1);
glTexCoord2d(1,1); glVertex2d( 1,-1);
glTexCoord2d(0,1); glVertex2d(-1,-1);
glEnd();
}
void player_actions(int *args)
{
// Make this happen again
mainloopRegAction(player_actions, 10, 0);
// Is the player out of the world or player pressed respawn
if(player_pos[1] < -1000 || gpad_button_pressed(BUTTON_X))
{
// Make the player respawn
player_respawn();
// Reset the power
player_power = 0;
}
// Copy the current position
double nx = player_pos[0];
double ny = player_pos[1];
double nz = player_pos[2];
// Is this the editor
if(player_mode == PLAYER_EDITOR)
{
// Create the bullet
double bullet[3] = {player_pos[0], player_pos[1], player_pos[2]};
if(
(gpad_trigger_length(TRIGGER_RIGHT) >= 0.5 && !place_block_pressed) ||
(gpad_trigger_length(TRIGGER_LEFT) >= 0.5 && !break_block_pressed)
){
// While the bullet isnt touching anything
while(
block_isnt_solid((int)bullet[0], (int)bullet[1], (int)bullet[2]) &&
block_in_world((int)bullet[0], (int)bullet[1], (int)bullet[2])
){
// Move the bullet
double y_movement = sin((player_angle[1]+90)*(PI/180.0));
bullet[0] += -cos((player_angle[0]+90)*(PI/180.0))*y_movement*0.01;
bullet[2] += -sin((player_angle[0]+90)*(PI/180.0))*y_movement*0.01;
bullet[1] += cos((player_angle[1]+90)*(PI/180.0))*0.01;
}
// Place
if(gpad_trigger_length(TRIGGER_RIGHT) >= 0.5 && !place_block_pressed)
{
// Move the bullet
double y_movement = sin((player_angle[1]+90)*(PI/180.0));
bullet[0] -= -cos((player_angle[0]+90)*(PI/180.0))*y_movement*0.01;
bullet[2] -= -sin((player_angle[0]+90)*(PI/180.0))*y_movement*0.01;
bullet[1] -= cos((player_angle[1]+90)*(PI/180.0))*0.01;
// Set a block
if(block_in_world((int)bullet[0], (int)bullet[1], (int)bullet[2])) {
set_block_at((int)bullet[0], (int)bullet[1], (int)bullet[2], BLOCK_STONE);
}
// Set the place block check varible to true
place_block_pressed = true;
}
// Break
if(gpad_trigger_length(TRIGGER_LEFT) >= 0.5 && !break_block_pressed)
{
// Set an air block
if(block_in_world((int)bullet[0], (int)bullet[1], (int)bullet[2])) {
set_block_at((int)bullet[0], (int)bullet[1], (int)bullet[2], BLOCK_AIR);
}
// Set the break block check varible to true
break_block_pressed = true;
}
}
// Place block button released
if(gpad_trigger_length(TRIGGER_RIGHT) < 0.5 && place_block_pressed)
{
// Reset the check varible
place_block_pressed = false;
}
// Break block button released
if(gpad_trigger_length(TRIGGER_LEFT) < 0.5 && break_block_pressed)
{
// Reset the check varible
break_block_pressed = false;
}
// Set the default movement power
double power = 0.1;
// Is the up button pressed
if(gpad_button_pressed(BUTTON_A))
{
// Go up
ny += power;
}
// Is the down button pressed
if(gpad_button_pressed(BUTTON_B))
{
// Go down
ny -= power;
}
// Get the stick values
float lx, ly, rx, ry;
gpad_stick_value(STICK_LEFT, lx, ly);
gpad_stick_value(STICK_RIGHT, rx, ry);
// Set the movement values
nx += -cos((player_angle[0]+90)*(PI/180.0))*ly*power;
nz += -sin((player_angle[0]+90)*(PI/180.0))*ly*power;
nx += -cos((player_angle[0]+180)*(PI/180.0))*lx*power;
nz += -sin((player_angle[0]+180)*(PI/180.0))*lx*power;
// Change the players angle
player_angle[0] += rx;
player_angle[1] -= ry;
}
else
{
// Can the user move
bool can_move = true;
// Is the player a boat
if(player_mode == PLAYER_BOAT)
{
// Is their water under the player
can_move = block_is_fluid(player_pos[0], player_pos[1]-1, player_pos[2]);
}
// Can the user move
if(can_move)
{
// Add power
player_power += 0.000002*gpad_trigger_length(TRIGGER_RIGHT);
// Add reverse power
player_power -= 0.000002*gpad_trigger_length(TRIGGER_LEFT);
}
// Is the power positive
if(player_power > 0)
{
// Reduce some power
player_power -= 0.0000001;
}
// Is the power negative
else if(player_power < 0)
{
// Reduce some power in the other direction
player_power += 0.0000001;
}
// Is the power too low
if(player_power < -player_max_speed)
{
// Set the value to the fastest speed
player_power = -player_max_speed;
}
// Is the power too high
if(player_power > player_max_speed)
{
// Set it to the maximum
player_power = player_max_speed;
}
// Make the player go forward
double p = sin((player_power/player_max_speed*90.0)*(PI/180.0));
nx += -cos((player_angle[0]+90)*(PI/180.0))*p;
nz += -sin((player_angle[0]+90)*(PI/180.0))*p;
// Change the angle
float lx, ly;
gpad_stick_value(STICK_LEFT, lx, ly);
double max_turn = PI/32.0;
// Can the user change the angle
if(can_move)
{
// Too sharp turn forwards
if(p>max_turn)
{
// Reset the angle
player_angle[0] += lx*max_turn*10;
}
// Too sharp turn backwards
else if(p<-max_turn)
{
// Reset the angle
player_angle[0] += lx*-max_turn*10;
}
else
{
// Turn due to speed
player_angle[0] += lx*p*10;
}
}
if(
// Is the player in water
block_is_fluid(player_pos[0], player_pos[1], player_pos[2]) &&
// Is the player a boat
player_mode == PLAYER_BOAT
){
// Increase the falling varible negatively
if(fall_speed > 0) fall_speed -= 0.008;
else fall_speed -= 0.004;
// Make the player fall
ny -= fall_speed;
}
// Is there air under the player
else if(block_isnt_solid(player_pos[0], player_pos[1]-1, player_pos[2]))
{
// Increase the falling varible
if(fall_speed < 0) fall_speed += 0.008;
else fall_speed += 0.004;
// Make the player fall
ny -= fall_speed;
}
}
// Is the angle out of range
while(player_angle[0] > 360) player_angle[0] -= 360;
while(player_angle[0] < 0) player_angle[0] += 360;
if(player_angle[1] > 90) player_angle[1] = 90;
if(player_angle[1] < -90) player_angle[1] = -90;
/*// Is the move valid
if(block_is_air(nx, ny, nz))
{
// Update the position
player_pos[0] = nx;
player_pos[1] = ny;
player_pos[2] = nz;
}*/
double invert_multiply = -0.25;
if(
block_isnt_solid(player_pos[0], ny, player_pos[2]) &&
block_isnt_solid(player_pos[0], ny-1, player_pos[2])
){
// Update the position
player_pos[1] = ny;
}
else
{
// Stop falling
fall_speed = 0;
}
// Is the move valid
if(block_isnt_solid(nx, player_pos[1], player_pos[2]))
{
// Is the lower block solid
while(
!block_isnt_solid(nx, player_pos[1]-1, player_pos[2]) &&
block_isnt_solid(player_pos[0], ny+1, player_pos[2])
){
// Teleport the player up it
player_pos[1] += 0.01;
}
// Update the position
player_pos[0] = nx;
}
else
{
// Invert the player motion
player_power *= invert_multiply;
}
if(block_isnt_solid(player_pos[0], player_pos[1], nz))
{
// Is the lower block solid
while(
!block_isnt_solid(player_pos[0], player_pos[1]-1, nz) &&
block_isnt_solid(player_pos[0], ny+1, player_pos[2])
){
// Teleport the player up it
player_pos[1] += 0.01;
}
// Update the position
player_pos[2] = nz;
}
else
{
// Invert the player motion
player_power *= invert_multiply;
}
}

13
player.h Normal file
View File

@ -0,0 +1,13 @@
#define PLAYER_CAR 0
#define PLAYER_BOAT 1
#define PLAYER_PLANE 2
#define PLAYER_EDITOR 3
extern double player_power;
extern double player_pos[3];
extern double player_angle[2];
extern int player_mode;
void player_init();
void player_render();
void player_actions(int*);

BIN
player.o Normal file

Binary file not shown.

0
random Normal file
View File

17
random.cpp Normal file
View File

@ -0,0 +1,17 @@
#include <fstream>
unsigned long long random_get_seed()
{
// Open the random device
std::ifstream rand_dev("/dev/urandom");
// Read some random bytes to get the seed
unsigned long long seed;
rand_dev.read((char*)&seed, sizeof(seed));
// Close the random device
rand_dev.close();
// Return the seed
return seed;
}

1
random.h Normal file
View File

@ -0,0 +1 @@
unsigned long long random_get_seed();

BIN
random.o Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

BIN
resources/textures/sky.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
src/blockracer Normal file

Binary file not shown.

BIN
src/resources.bin Normal file

Binary file not shown.

75
text.cpp Normal file
View File

@ -0,0 +1,75 @@
#include <GL/glut.h>
#include <string>
#include "textures.h"
int render_7_seg_img;
void render_7_seg_part(int id, double size)
{
// Start drawing
glBegin(GL_QUADS);
glTexCoord2d((id+0)/11.0, 0); glVertex2d(0 ,0 );
glTexCoord2d((id+1)/11.0, 0); glVertex2d(size,0 );
glTexCoord2d((id+1)/11.0, 1); glVertex2d(size,size);
glTexCoord2d((id+0)/11.0, 1); glVertex2d(0 ,size);
// Stop drawing
glEnd();
}
void render_7_seg(unsigned long n, double size, int places)
{
// Bind the texture
glBindTexture(GL_TEXTURE_2D, render_7_seg_img);
// Convert the number to a string
std::string str = std::to_string(n);
// Is the place count negative, by default
if(places == -1)
{
// Set the places to display as the string size
places = str.size();
}
// Loop over the places
for(int i=0;i<places;i++)
{
// Is the iterator too large
if(i >= str.size())
{
// Render a blank pane
render_7_seg_part(10, size);
}
else
{
// Get part of the number to view
char item = str[str.size()-i];
// Render the item
if(item=='0') render_7_seg_part(0, size);
if(item=='1') render_7_seg_part(1, size);
if(item=='2') render_7_seg_part(2, size);
if(item=='3') render_7_seg_part(3, size);
if(item=='4') render_7_seg_part(4, size);
if(item=='5') render_7_seg_part(5, size);
if(item=='6') render_7_seg_part(6, size);
if(item=='7') render_7_seg_part(7, size);
if(item=='8') render_7_seg_part(8, size);
if(item=='9') render_7_seg_part(9, size);
}
}
// Unbind the image
glBindTexture(GL_TEXTURE_2D, 0);
}
void text_init()
{
// Load the 7 segment display
int w, h;
render_7_seg_img = loadArchiveImageGL("textures/7-seg.rimg", 'L', w, h);
}

2
text.h Normal file
View File

@ -0,0 +1,2 @@
void render_7_seg(unsigned long n, double size, int places);
void text_init();

BIN
text.o Normal file

Binary file not shown.

198
textures.cpp Normal file
View File

@ -0,0 +1,198 @@
#include <fstream>
#include <string.h>
#include <GL/glut.h>
#include "textures.h"
#include "archive.h"
void read_from_string(char *str, int &place, char* data, int32_t size)
{
// Iterate over the string
for(int i=0;(i<size)&&(i<place+size);i++)
{
// Set part of the c string as the data
data[i] = (char)str[i+place];
}
// Add to the place
place += size;
}
char* combineImages(char* image_1, int imagesize_1, char* image_2, int imagesize_2,
int &imageout_size)
{
// Setup the dimentions varibles
uint32_t w1, h1, w2, h2;
int it1 = 0;
int it2 = 0;
// Get the dimentions
read_from_string(image_1, it1, (char*)&w1, sizeof(w1));
read_from_string(image_1, it1, (char*)&h1, sizeof(h1));
read_from_string(image_2, it2, (char*)&w2, sizeof(w2));
read_from_string(image_2, it2, (char*)&h2, sizeof(h2));
// Setup the images varibles
char* pix1 = new char[w1*h1*4];
char* pix2 = new char[w2*h2*4];
// Get the images
read_from_string(image_1, it1, pix1, w1*h1*4);
read_from_string(image_2, it2, pix2, w2*h2*4);
// Create a texture
std::string image_R;
// Set the size
uint32_t wR = w1;
uint32_t hR = h1+h2;
// Add the size to the texture
image_R.append((char*)&wR, sizeof(wR));
image_R.append((char*)&hR, sizeof(hR));
// Loop over image 1
for(int i=0;i<w1*h1*4;i++)
{
// Add part of image 1 to the texture
image_R += pix1[i];
}
// Loop over image 2
for(int i=0;i<w2*h2*4;i++)
{
// Add part of image 2 to the texture
image_R += pix2[i];
}
// Free the pixel data
free(pix1);
free(pix2);
// Convert the string to char array
int returnsize = image_R.size();
char* returndata = new char[returnsize];
// Loop over the image
for(int i=0;i<returnsize;i++)
{
// Set part of the string to part of the c string
returndata[i] = image_R[i];
}
// Return the data
return returndata;
}
unsigned int loadPixels(char *cpixels, int width, int height, char filter, bool unbind_texture)
{
// Convert the pixels to GLubyte
GLubyte *pixels = (GLubyte*)cpixels;
// Create the texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width,
height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Linear
if(filter == 'L') {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
}
// Nearest
if(filter == 'N') {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
}
// Does the user want to unbind the texture
if(unbind_texture)
{
// Unbind the texture
glBindTexture(GL_TEXTURE_2D, 0);
}
// Return the address
return tex;
}
char* loadImage(const char *dir, int &width, int &height)
{
// Open the file
std::ifstream file;
file.open(dir, std::ios::binary);
// Get the dimentions
int32_t w, h;
file.read((char*)&w, sizeof(w));
file.read((char*)&h, sizeof(h));
width = w;
height = h;
// Get the binary data
char *pixels = new char[width*height*4];
file.read(pixels, width*height*4);
// Close the file
file.close();
// Return the binary data
return pixels;
}
unsigned int loadImageGL(const char *dir, char filter, int &width, int &height)
{
// Get the data
char *pixels = loadImage(dir, width, height);
// Return the OpenGL texture
return loadPixels(pixels, width, height, filter);
}
unsigned int loadImageDataGL(char *data, int size, char filter, int &width, int &height)
{
// Setup the iterator
int i = 0;
// Get the width and height
int32_t w, h;
read_from_string(data, i, (char*)&w, sizeof(w));
read_from_string(data, i, (char*)&h, sizeof(h));
width = w;
height = h;
// Get the pixels
char* pixels = new char[w*h*4];
read_from_string(data, i, pixels, w*h*4);
// Load the image
int image = loadPixels(pixels, width, height, filter);
// Free the pixel data
free(pixels);
// Return the image
return image;
}
unsigned int loadArchiveImageGL(const char *dir, int filter, int &width, int &height)
{
// Get the file data position
ArchivePos apos = archiveGetPos(archive, dir);
// Get the file data
char* data = new char[apos.size];
archiveRead(archive, apos, data);
// Load the image
int image = loadImageDataGL(data, (int)apos.size, filter, width, height);
// Free the file data
free(data);
// Return the image
return image;
}

7
textures.h Normal file
View File

@ -0,0 +1,7 @@
unsigned int loadPixels(char *pixels, int width, int height, char filter, bool unbind_texure=true);
char* loadImage(const char *dir, int &width, int &height);
unsigned int loadImageGL(const char *dir, char filter, int &width, int &height);
unsigned int loadImageDataGL(char *data, int size, char filter, int &width, int &height);
unsigned int loadArchiveImageGL(const char *dir, int filter, int &width, int &height);
char* combineImages(char* image_1, int imagesize_1, char* image_2, int imagesize_2,
int &imageout_size);

BIN
textures.o Normal file

Binary file not shown.

603
world.cpp Normal file
View File

@ -0,0 +1,603 @@
#include <GL/glut.h>
#include <fstream>
#include <iostream>
#include <random>
#include <vector>
#include <math.h>
#include "PerlinNoise.hpp"
#include "random.h"
#include "graphics.h"
#include "blocks.h"
#include "player.h"
#include "world.h"
#include "math.h"
//int min_render_distance=50;
int render_distance_width=40;
int render_distance_height=10;
uint64_t sxyz[3];
Block *world;
/*std::vector<double> render_distance_average;
void on_early()
{
// Increase the render distance
render_distance += 1;
}
void on_late()
{
// Reduce the render distance
if(render_distance > min_render_distance) {
render_distance -= 1;
}
}
*/
void coords_to_int(int *id, int x, int y, int z) {
*id = z * sxyz[1] * sxyz[0] + y * sxyz[0] + x;
}
void int_to_coords(int id, int *x, int *y, int *z) {
*x = id % sxyz[0];
*y = (id/sxyz[0]) % sxyz[1];
*z = (id/sxyz[0]/sxyz[1]) % sxyz[2];
}
// Say if the block is in the world
bool block_in_world(int x, int y, int z) {
return (x >= 0) && (x < sxyz[0]) && (y >= 0) && (y < sxyz[1]) && (z >= 0) && (z < sxyz[2]);
}
// Say if the player is in the world
bool player_in_world(double x, double y, double z) {
return (x >= 0) && (x <= sxyz[0]) && (y >= 0) && (y <= sxyz[1]) && (z >= 0) && (z <= sxyz[2]);
}
bool block_is_ramp(double x, double y, double z)
{
// Get the id
int id;
coords_to_int(&id, x, y, z);
// Is the player on a ramp
if(world[id].type == BTYPE_RAMP)
{
// Get the part of the slope the player is on
double slope_part;
// North
if(world[id].direction == DIRECTION_N)
{
slope_part = 1-(z-int(z));
}
// South
if(world[id].direction == DIRECTION_S)
{
slope_part = z-int(z);
}
// East
if(world[id].direction == DIRECTION_E)
{
slope_part = 1-(x-int(x));
}
// West
if(world[id].direction == DIRECTION_W)
{
slope_part = x-int(x);
}
// Is the player above the slope part
return ((y-int(y)) < slope_part+0.25);
}
// The player isnt on a ramp
return false;
}
bool block_isnt_solid(double x, double y, double z)
{
// Setup some varibles
bool in_world_check = false;
double d = 0.25;
// Is the player inside the world
if(player_in_world(x, y, z)) in_world_check = true;
// Is the block in range
if(in_world_check)
{
if(block_is_ramp(x, y, z))
{
return false;
}
// Get the ids
int id[8];
coords_to_int(&id[0], x+d, y+d, z+d);
coords_to_int(&id[1], x-d, y+d, z+d);
coords_to_int(&id[2], x-d, y+d, z-d);
coords_to_int(&id[3], x+d, y+d, z-d);
coords_to_int(&id[4], x+d, y-d, z+d);
coords_to_int(&id[5], x-d, y-d, z+d);
coords_to_int(&id[6], x-d, y-d, z-d);
coords_to_int(&id[7], x+d, y-d, z-d);
// Loop throgh the ids
for(int i=0;i<8;i++)
{
// Convert the id to coordinates
int cx, cy, cz;
int_to_coords(id[i], &cx, &cy, &cz);
// Are the coordinates out of range; then return true
if(cx < 0 || cy < 0 || cz < 0 || cx >= sxyz[0] || cy >= sxyz[1] || cz >= sxyz[2]) {
return true;
}
// Is the block not in the world
if(!block_in_world(cx, cy, cz))
{
// Return true
return true;
}
// Return false if this is not air and is a block
if(
world[id[i]].id != BLOCK_AIR &&
world[id[i]].type == BTYPE_BLOCK
) return false;
}
// Return true
return true;
}
// Return true
return true;
}
bool block_is_fluid(double x, double y, double z)
{
// Get the fluid motion
double fluid_motion = get_fluid_motion(x, z);
// Get the id
int id;
coords_to_int(&id, x, y+1-fluid_motion, z);
// Get the above id
int a_id;
coords_to_int(&a_id, x, y+2-fluid_motion, z);
// Is the player in a fluid
if(world[id].type == BTYPE_FLUID)
{
// Submurged under the water
if(world[a_id].type == BTYPE_FLUID)
{
// Return true
return true;
}
// Is the decimal height greater than the block height and the fluid motion
return y < int(y) + fluid_motion;
}
// Return false
return false;
}
int relative_block(int id, int x, int y, int z)
{
// Get the position of the current block
int cx, cy, cz;
int_to_coords(id, &cx, &cy, &cz);
// Add the relative coordinates
cx += x;
cy += y;
cz += z;
// Is this valid
if(cx < 0) return -1;
if(cy < 0) return -1;
if(cz < 0) return -1;
if(cx >= sxyz[0]) return -1;
if(cy >= sxyz[1]) return -1;
if(cz >= sxyz[2]) return -1;
// Get the id
int cid;
coords_to_int(&cid, cx, cy, cz);
// Return the block id
return cid;
}
bool relative_block_optimise(int id, int x, int y, int z, bool check)
{
// Is the check varible already false
if(!check) return false;
// Get the id of the relative block
int rb = relative_block(id, x, y, z);
// Is the result out of range (-1)
if(rb == -1) return false;
if(!(
// Is not air
world[rb].id != BLOCK_AIR &&
(
// Is the same type as the other block
world[rb].type == world[id].type ||
// Is the other block a block
world[rb].type == BTYPE_BLOCK
)
)) return true;
return (
(!blockGetSettings(world[id].id).transparent) &&
blockGetSettings(world[rb].id).transparent
);
/*// Check the angle of the face and the player
// Get the blocks coordinates
int cx, cy, cz;
int_to_coords(id, &cx, &cy, &cz);
double a;
if(x != 0 || z != 0)
{
a = atan2(cx-player_pos[0], cz-player_pos[2])*180.0/PI
}
// North / South
if(x != 0)
{
// Get the angle
a -= player_angle[0];
a *= x;
}
// East / West
if(z != 0)
{
// Get the angle
a = ;
a -= player_angle[0] - 90;
a *= z;
}
// Up / Down
if(y != 0)
{
// Get the angle
a = atan2(cy-player_pos[1], cz-player_pos[2])*180.0/PI;
a -= player_angle[0];
a *= y;
}
// Fix the angle
while(a < 0) a += 360;
while(a > 360) a -= 360;
return a > 0 && a < 180;*/
}
void world_load(const char *dir)
{
/*// Open the file
std::ifstream file(dir, std::ios::binary);
// Load the map size
file.read((char*)&sxyz[0], sizeof(uint64_t));
file.read((char*)&sxyz[1], sizeof(uint64_t));
file.read((char*)&sxyz[2], sizeof(uint64_t));
// Setup the world varible
world = new World[sxyz[0]*sxyz[1]*sxyz[2]];
// Read the world data
file.read((char*)world, sizeof(World)*sxyz[0]*sxyz[1]*sxyz[2]);
// Close the file
file.close();*/
}
void player_respawn()
{
// Set the player to the middle and at the top of the map
player_pos[0] = sxyz[0]/2;
player_pos[1] = sxyz[1]-2;
player_pos[2] = sxyz[2]/2;
}
void world_init()
{
// Initialse the blocks
blocks_init();
sxyz[0] = 256;
sxyz[1] = 120;
sxyz[2] = 256;
// Set the players spawn point
player_respawn();
// Setup the world varible
world = new Block[sxyz[0]*sxyz[1]*sxyz[2]];
// Zero out the world varible
zero_out_bytes((char*)world, sizeof(Block)*sxyz[0]*sxyz[1]*sxyz[2]);
// Set the seed
const siv::PerlinNoise perlin(random_get_seed());
// Set the frequency
double frequency = 1;
double xf = sxyz[0] / frequency;
double zf = sxyz[2] / frequency;
// Loop over x
for(int x=0;x<sxyz[0];x++)
{
// Loop over z
for(int z=0;z<sxyz[2];z++)
{
// Get some perlin noise
double f = 128;
int noise = perlin.octaveNoise0_1(x / f, z / f, 8)*100;
// Go up the world
for(int y=0;y<sxyz[1];y++)
{
// Get the id
int id;
coords_to_int(&id, x, y, z);
// Edge of the world
if(x == 0 || z == 0 || x == sxyz[0]-1 || z == sxyz[2]-1 || y == 0 || y == sxyz[1]-1)
{
// Set the block to a barrier
world[id] = make_block(BLOCK_BARRIER);
}
else
{
// 2 blocks under the ground
if(y < noise-2)
{
// Make stone
world[id] = make_block(BLOCK_STONE);
}
// Under the ground
else if(y < noise)
{
// Make dirt
world[id] = make_block(BLOCK_DIRT);
}
// At ground level
else if(y == noise && y >= 60)
{
// Make grass
world[id] = make_block(BLOCK_GRASS);
}
else if(y == noise && y < 60)
{
// Make grass
world[id] = make_block(BLOCK_SAND);
}
// Water level
else if(y > noise && y < 60)
{
// Make water
world[id] = make_block(BLOCK_WATER, BTYPE_FLUID);
}
// 1 block above ground
else if(y == noise+1)
{
// Get some perlin noise
double grass_noise = perlin.octaveNoise0_1(x / 10.0, z / 10.0, 10);
// Over a certain threshold
if(grass_noise > 0.6)
{
// Make grass plant
world[id] = make_block(BLOCK_GRASS_PLANT, BTYPE_PLANT);
}
}
}
/*
else if(y < 2)
{
world[id] = make_block(BLOCK_DIRT);
}
else if(y == 2)
{
world[id] = make_block(BLOCK_GRASS);
}
else if(x > 5 && y < z-100)
{
world[id] = make_block(BLOCK_DIRT);
}
else if(x > 5 && y == z-100)
{
world[id] = make_block(BLOCK_GRASS, BTYPE_RAMP, DIRECTION_S);
}
*/
}
}
}
}
void render_coord(int x, int y, int z, int a1, int a2)
{
// Is this in range
if(block_in_world(x, y, z))
{
// Get the id
int id;
coords_to_int(&id, x, y, z);
int b = 60;
// Is this not air
if(world[id].id != BLOCK_AIR)
{
// Setup a Block Face Map
BlockFaceMap fm;
fm.n = relative_block_optimise(id, 0, 0,-1, a1 > 90 -b && a1 < 270+b || (a2 < -40 || a2 > 40));
fm.s = relative_block_optimise(id, 0, 0, 1, a1 > 270-b || a1 < 90 +b || (a2 < -40 || a2 > 40));
fm.e = relative_block_optimise(id, 1, 0, 0, a1 < 0 +b || a1 > 180-b || (a2 < -40 || a2 > 40));
fm.w = relative_block_optimise(id,-1, 0, 0, a1 < 180+b || a1 > 360-b || (a2 < -40 || a2 > 40));
fm.t = relative_block_optimise(id, 0, 1, 0, a2 > 0-b || world[id].type == BTYPE_FLUID);
fm.b = relative_block_optimise(id, 0,-1, 0, a2 < 0+b);
// Render the block
render_block(world[id], x, y, z, fm);
}
}
}
void world_render_block_inside_player()
{
// Bind the texture
bind_block_texture();
// Get the id
int id;
coords_to_int(&id, player_pos[0], player_pos[1], player_pos[2]);
// Render the block face infront of the player
render_block_face_here(world[id]);
}
void world_render()
{
// Set the colour to maximum opacity and colour
glColor4f(1.0f,1.0f,1.0f,1.0f);
// Bind the texture
bind_block_texture();
// Get the cameras angles
int a1 = (int)player_angle[0] % 360;
int a2 = (int)player_angle[1] % 180;
// Set the cutof render angles
int g1 = 80;
int g2 = 40;
// Render everything inwards
for(int x=render_distance_width;x>0;x-=1) {
for(int y=render_distance_height;y>0;y-=1) {
for(int z=render_distance_width;z>0;z-=1)
{
// Render the blocks
if((a1 < 180 +g1 && a1 > 90 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]+x, player_pos[1]+y, player_pos[2]+z, a1, a2);
if((a1 < 270 +g1 && a1 > 180 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]-x, player_pos[1]+y, player_pos[2]+z, a1, a2);
if((a1 < 0 +g1 || a1 > 270 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]-x, player_pos[1]+y, player_pos[2]-z, a1, a2);
if((a1 < 90 +g1 || a1 > 360 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]+x, player_pos[1]+y, player_pos[2]-z, a1, a2);
if((a1 < 180 +g1 && a1 > 90 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]+x, player_pos[1]-y, player_pos[2]+z, a1, a2);
if((a1 < 270 +g1 && a1 > 180 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]-x, player_pos[1]-y, player_pos[2]+z, a1, a2);
if((a1 < 0 +g1 || a1 > 270 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]-x, player_pos[1]-y, player_pos[2]-z, a1, a2);
if((a1 < 90 +g1 || a1 > 360 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]+x, player_pos[1]-y, player_pos[2]-z, a1, a2);
}
}
}
for(int x=render_distance_width;x>0;x-=1) {
for(int z=render_distance_width;z>0;z-=1)
{
// Render the coordinates
render_coord(player_pos[0]+x, player_pos[1], player_pos[2]+z, a1, a2);
render_coord(player_pos[0]+x, player_pos[1], player_pos[2]-z, a1, a2);
render_coord(player_pos[0]-x, player_pos[1], player_pos[2]-z, a1, a2);
render_coord(player_pos[0]-x, player_pos[1], player_pos[2]+z, a1, a2);
}
}
for(int x=render_distance_width;x>0;x-=1) {
for(int y=render_distance_height;y>0;y-=1)
{
// Render the coordinates
render_coord(player_pos[0]+x, player_pos[1]+y, player_pos[2], a1, a2);
render_coord(player_pos[0]+x, player_pos[1]-y, player_pos[2], a1, a2);
render_coord(player_pos[0]-x, player_pos[1]-y, player_pos[2], a1, a2);
render_coord(player_pos[0]-x, player_pos[1]+y, player_pos[2], a1, a2);
}
}
for(int z=render_distance_width;z>0;z-=1) {
for(int y=render_distance_height;y>0;y-=1)
{
// Render the coordinates
render_coord(player_pos[0], player_pos[1]+y, player_pos[2]+z, a1, a2);
render_coord(player_pos[0], player_pos[1]+y, player_pos[2]-z, a1, a2);
render_coord(player_pos[0], player_pos[1]-y, player_pos[2]-z, a1, a2);
render_coord(player_pos[0], player_pos[1]-y, player_pos[2]+z, a1, a2);
}
}
for(int x=render_distance_width;x>0;x-=1)
{
// Render the coordinates
render_coord(player_pos[0]+x, player_pos[1], player_pos[2], a1, a2);
render_coord(player_pos[0]-x, player_pos[1], player_pos[2], a1, a2);
}
for(int y=render_distance_height;y>0;y-=1)
{
// Render the coordinates
render_coord(player_pos[0], player_pos[1]+y, player_pos[2], a1, a2);
render_coord(player_pos[0], player_pos[1]-y, player_pos[2], a1, a2);
}
for(int z=render_distance_width;z>0;z-=1)
{
// Render the coordinates
render_coord(player_pos[0], player_pos[1], player_pos[2]+z, a1, a2);
render_coord(player_pos[0], player_pos[1], player_pos[2]-z, a1, a2);
}
// Render a coordinate where the player is standing
render_coord(player_pos[0], player_pos[1], player_pos[2], a1, a2);
// Unbind the texture
unbind_block_texture();
// Enable blending
//glEnable(GL_BLEND);
}
void set_block_at(int x, int y, int z, uint8_t id, uint8_t type, uint8_t direction)
{
// Get the id
int w_id;
coords_to_int(&w_id, x, y, z);
// Get the block
Block b = make_block(id, type, direction);
// Set the block
world[w_id] = b;
}

12
world.h Normal file
View File

@ -0,0 +1,12 @@
#include <cstdint>
void world_init();
void world_render();
bool block_isnt_solid(double x, double y, double z);
bool block_is_fluid(double x, double y, double z);
void player_respawn();
void world_render_block_inside_player();
void set_block_at(int x, int y, int z, uint8_t id, uint8_t type=0, uint8_t direction=0);
bool block_in_world(int x, int y, int z);
//void on_early();
//void on_late();

BIN
world.o Normal file

Binary file not shown.

1912
zlib.h Normal file

File diff suppressed because it is too large Load Diff