mirror of
https://github.com/nothings/stb
synced 2024-12-15 04:22:35 +03:00
initial stb_voxel_render version with working minecraft viewer
This commit is contained in:
parent
bdef693b7c
commit
2770c92148
2097
stb_voxel_render.h
Normal file
2097
stb_voxel_render.h
Normal file
File diff suppressed because it is too large
Load Diff
644
tests/caveview/cave_parse.c
Normal file
644
tests/caveview/cave_parse.c
Normal file
@ -0,0 +1,644 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FAST_CHUNK // disabling this enables the old, slower path that deblocks into a regular form
|
||||
|
||||
#include "cave_parse.h"
|
||||
|
||||
#include "stb_image.h"
|
||||
#include "stb.h"
|
||||
|
||||
// @TODO: need to unload LRU compressed chunks
|
||||
|
||||
#define NUM_CHUNKS_PER_REGION 32 // only on one axis
|
||||
#define NUM_CHUNKS_PER_REGION_LOG2 5
|
||||
|
||||
#define NUM_COLUMNS_PER_CHUNK 16
|
||||
#define NUM_COLUMNS_PER_CHUNK_LOG2 4
|
||||
|
||||
uint32 read_uint32_be(FILE *f)
|
||||
{
|
||||
unsigned char data[4];
|
||||
fread(data, 1, 4, f);
|
||||
return (data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3];
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8 *data;
|
||||
size_t len;
|
||||
int x,z; // chunk index
|
||||
int refcount; // for multi-threading
|
||||
} compressed_chunk;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,z;
|
||||
uint32 sector_data[NUM_CHUNKS_PER_REGION][NUM_CHUNKS_PER_REGION];
|
||||
} region;
|
||||
|
||||
size_t cached_compressed=0;
|
||||
|
||||
FILE *last_region;
|
||||
int last_region_x;
|
||||
int last_region_z;
|
||||
int opened=0;
|
||||
|
||||
static void open_file(int reg_x, int reg_z)
|
||||
{
|
||||
if (!opened || last_region_x != reg_x || last_region_z != reg_z) {
|
||||
char filename[256];
|
||||
if (last_region != NULL)
|
||||
fclose(last_region);
|
||||
sprintf(filename, "r.%d.%d.mca", reg_x, reg_z);
|
||||
last_region = fopen(filename, "rb");
|
||||
last_region_x = reg_x;
|
||||
last_region_z = reg_z;
|
||||
opened = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static region *load_region(int reg_x, int reg_z)
|
||||
{
|
||||
region *r;
|
||||
int x,z;
|
||||
|
||||
open_file(reg_x, reg_z);
|
||||
|
||||
r = malloc(sizeof(*r));
|
||||
|
||||
if (last_region == NULL) {
|
||||
memset(r, 0, sizeof(*r));
|
||||
} else {
|
||||
fseek(last_region, 0, SEEK_SET);
|
||||
for (z=0; z < NUM_CHUNKS_PER_REGION; ++z)
|
||||
for (x=0; x < NUM_CHUNKS_PER_REGION; ++x)
|
||||
r->sector_data[z][x] = read_uint32_be(last_region);
|
||||
}
|
||||
r->x = reg_x;
|
||||
r->z = reg_z;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void free_region(region *r)
|
||||
{
|
||||
free(r);
|
||||
}
|
||||
|
||||
#define MAX_MAP_REGIONS 64 // in one axis: 64 regions * 32 chunk/region * 16 columns/chunk = 16384 columns
|
||||
region *regions[MAX_MAP_REGIONS][MAX_MAP_REGIONS];
|
||||
|
||||
static region *get_region(int reg_x, int reg_z)
|
||||
{
|
||||
int slot_x = reg_x & (MAX_MAP_REGIONS-1);
|
||||
int slot_z = reg_z & (MAX_MAP_REGIONS-1);
|
||||
region *r;
|
||||
|
||||
r = regions[slot_z][slot_x];
|
||||
|
||||
if (r) {
|
||||
if (r->x == reg_x && r->z == reg_z)
|
||||
return r;
|
||||
free_region(r);
|
||||
}
|
||||
|
||||
r = load_region(reg_x, reg_z);
|
||||
regions[slot_z][slot_x] = r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// about one region, so size should be ok
|
||||
#define NUM_CACHED_X 64
|
||||
#define NUM_CACHED_Z 64
|
||||
|
||||
// @TODO: is it really worth caching these? we probably can just
|
||||
// pull them from the disk cache nearly as efficiently.
|
||||
// Can test that by setting to 1x1?
|
||||
compressed_chunk *cached_chunk[NUM_CACHED_Z][NUM_CACHED_X];
|
||||
|
||||
static void deref_compressed_chunk(compressed_chunk *cc)
|
||||
{
|
||||
assert(cc->refcount > 0);
|
||||
--cc->refcount;
|
||||
if (cc->refcount == 0) {
|
||||
if (cc->data)
|
||||
free(cc->data);
|
||||
free(cc);
|
||||
}
|
||||
}
|
||||
|
||||
static compressed_chunk *get_compressed_chunk(int chunk_x, int chunk_z)
|
||||
{
|
||||
int slot_x = chunk_x & (NUM_CACHED_X-1);
|
||||
int slot_z = chunk_z & (NUM_CACHED_Z-1);
|
||||
compressed_chunk *cc = cached_chunk[slot_z][slot_x];
|
||||
|
||||
if (cc && cc->x == chunk_x && cc->z == chunk_z)
|
||||
return cc;
|
||||
else {
|
||||
int reg_x = chunk_x >> NUM_CHUNKS_PER_REGION_LOG2;
|
||||
int reg_z = chunk_z >> NUM_CHUNKS_PER_REGION_LOG2;
|
||||
region *r = get_region(reg_x, reg_z);
|
||||
if (cc) {
|
||||
deref_compressed_chunk(cc);
|
||||
cached_chunk[slot_z][slot_x] = NULL;
|
||||
}
|
||||
cc = malloc(sizeof(*cc));
|
||||
cc->x = chunk_x;
|
||||
cc->z = chunk_z;
|
||||
{
|
||||
int subchunk_x = chunk_x & (NUM_CHUNKS_PER_REGION-1);
|
||||
int subchunk_z = chunk_z & (NUM_CHUNKS_PER_REGION-1);
|
||||
uint32 code = r->sector_data[subchunk_z][subchunk_x];
|
||||
|
||||
if (code & 255) {
|
||||
open_file(reg_x, reg_z);
|
||||
fseek(last_region, (code>>8)*4096, SEEK_SET);
|
||||
cc->len = (code&255)*4096;
|
||||
cc->data = malloc(cc->len);
|
||||
fread(cc->data, 1, cc->len, last_region);
|
||||
} else {
|
||||
cc->len = 0;
|
||||
cc->data = 0;
|
||||
}
|
||||
}
|
||||
cc->refcount = 1;
|
||||
cached_chunk[slot_z][slot_x] = cc;
|
||||
return cc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NBT parser -- can automatically parse stuff we don't
|
||||
// have definitions for, but want to explicitly parse
|
||||
// stuff we do have definitions for.
|
||||
//
|
||||
// option 1: auto-parse everything into data structures,
|
||||
// then read those
|
||||
//
|
||||
// option 2: have a "parse next object" which
|
||||
// doesn't resolve whether it expands its children
|
||||
// yet, and then the user either says "expand" or
|
||||
// "skip" after looking at the name. Anything with
|
||||
// "children" without names can't go through this
|
||||
// interface.
|
||||
//
|
||||
// Let's try option 2.
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char *buffer_start;
|
||||
unsigned char *buffer_end;
|
||||
unsigned char *cur;
|
||||
int nesting;
|
||||
char temp_buffer[256];
|
||||
} nbt;
|
||||
|
||||
enum { TAG_End=0, TAG_Byte=1, TAG_Short=2, TAG_Int=3, TAG_Long=4,
|
||||
TAG_Float=5, TAG_Double=6, TAG_Byte_Array=7, TAG_String=8,
|
||||
TAG_List=9, TAG_Compound=10, TAG_Int_Array=11 };
|
||||
|
||||
static void nbt_get_string_data(unsigned char *data, char *buffer, size_t bufsize)
|
||||
{
|
||||
int len = data[0]*256 + data[1];
|
||||
int i;
|
||||
for (i=0; i < len && i+1 < (int) bufsize; ++i)
|
||||
buffer[i] = (char) data[i+2];
|
||||
buffer[i] = 0;
|
||||
}
|
||||
|
||||
static char *nbt_peek(nbt *n)
|
||||
{
|
||||
unsigned char type = *n->cur;
|
||||
if (type == TAG_End)
|
||||
return NULL;
|
||||
nbt_get_string_data(n->cur+1, n->temp_buffer, sizeof(n->temp_buffer));
|
||||
return n->temp_buffer;
|
||||
}
|
||||
|
||||
static uint32 nbt_parse_uint32(unsigned char *buffer)
|
||||
{
|
||||
return (buffer[0] << 24) + (buffer[1]<<16) + (buffer[2]<<8) + buffer[3];
|
||||
}
|
||||
|
||||
static void nbt_skip(nbt *n);
|
||||
|
||||
// skip an item that doesn't have an id or name prefix (usable in lists)
|
||||
static void nbt_skip_raw(nbt *n, unsigned char type)
|
||||
{
|
||||
switch (type) {
|
||||
case TAG_Byte : n->cur += 1; break;
|
||||
case TAG_Short : n->cur += 2; break;
|
||||
case TAG_Int : n->cur += 4; break;
|
||||
case TAG_Long : n->cur += 8; break;
|
||||
case TAG_Float : n->cur += 4; break;
|
||||
case TAG_Double: n->cur += 8; break;
|
||||
case TAG_Byte_Array: n->cur += 4 + 1*nbt_parse_uint32(n->cur); break;
|
||||
case TAG_Int_Array : n->cur += 4 + 4*nbt_parse_uint32(n->cur); break;
|
||||
case TAG_String : n->cur += 2 + (n->cur[0]*256 + n->cur[1]); break;
|
||||
case TAG_List : {
|
||||
unsigned char list_type = *n->cur++;
|
||||
unsigned int list_len = nbt_parse_uint32(n->cur);
|
||||
unsigned int i;
|
||||
n->cur += 4; // list_len
|
||||
for (i=0; i < list_len; ++i)
|
||||
nbt_skip_raw(n, list_type);
|
||||
break;
|
||||
}
|
||||
case TAG_Compound : {
|
||||
while (*n->cur != TAG_End)
|
||||
nbt_skip(n);
|
||||
nbt_skip(n); // skip the TAG_end
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(n->cur <= n->buffer_end);
|
||||
}
|
||||
|
||||
static void nbt_skip(nbt *n)
|
||||
{
|
||||
unsigned char type = *n->cur++;
|
||||
if (type == TAG_End)
|
||||
return;
|
||||
// skip name
|
||||
n->cur += (n->cur[0]*256 + n->cur[1]) + 2;
|
||||
nbt_skip_raw(n, type);
|
||||
}
|
||||
|
||||
// byteswap
|
||||
static void nbt_swap(unsigned char *ptr, int len)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < (len>>1); ++i) {
|
||||
unsigned char t = ptr[i];
|
||||
ptr[i] = ptr[len-1-i];
|
||||
ptr[len-1-i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
// pass in the expected type, fail if doesn't match
|
||||
// returns a pointer to the data, byteswapped if appropriate
|
||||
static void *nbt_get_fromlist(nbt *n, unsigned char type, int *len)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
assert(type != TAG_Compound);
|
||||
assert(type != TAG_List); // we could support getting lists of primitives as if they were arrays, but eh
|
||||
if (len) *len = 1;
|
||||
ptr = n->cur;
|
||||
switch (type) {
|
||||
case TAG_Byte : break;
|
||||
|
||||
case TAG_Short : nbt_swap(ptr, 2); break;
|
||||
case TAG_Int : nbt_swap(ptr, 4); break;
|
||||
case TAG_Long : nbt_swap(ptr, 8); break;
|
||||
case TAG_Float : nbt_swap(ptr, 4); break;
|
||||
case TAG_Double: nbt_swap(ptr, 8); break;
|
||||
|
||||
case TAG_Byte_Array:
|
||||
*len = nbt_parse_uint32(ptr);
|
||||
ptr += 4;
|
||||
break;
|
||||
case TAG_Int_Array: {
|
||||
int i;
|
||||
*len = nbt_parse_uint32(ptr);
|
||||
ptr += 4;
|
||||
for (i=0; i < *len; ++i)
|
||||
nbt_swap(ptr + 4*i, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
default: assert(0); // unhandled case
|
||||
}
|
||||
nbt_skip_raw(n, type);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *nbt_get(nbt *n, unsigned char type, int *len)
|
||||
{
|
||||
assert(n->cur[0] == type);
|
||||
n->cur += 3 + (n->cur[1]*256+n->cur[2]);
|
||||
return nbt_get_fromlist(n, type, len);
|
||||
}
|
||||
|
||||
static void nbt_begin_compound(nbt *n) // start a compound
|
||||
{
|
||||
assert(*n->cur == TAG_Compound);
|
||||
// skip header
|
||||
n->cur += 3 + (n->cur[1]*256 + n->cur[2]);
|
||||
++n->nesting;
|
||||
}
|
||||
|
||||
static void nbt_begin_compound_in_list(nbt *n) // start a compound
|
||||
{
|
||||
++n->nesting;
|
||||
}
|
||||
|
||||
static void nbt_end_compound(nbt *n) // end a compound
|
||||
{
|
||||
assert(*n->cur == TAG_End);
|
||||
assert(n->nesting != 0);
|
||||
++n->cur;
|
||||
--n->nesting;
|
||||
}
|
||||
|
||||
// @TODO no interface to get lists from lists
|
||||
static int nbt_begin_list(nbt *n, unsigned char type)
|
||||
{
|
||||
uint32 len;
|
||||
unsigned char *ptr;
|
||||
|
||||
ptr = n->cur + 3 + (n->cur[1]*256 + n->cur[2]);
|
||||
if (ptr[0] != type)
|
||||
return -1;
|
||||
n->cur = ptr;
|
||||
len = nbt_parse_uint32(n->cur+1);
|
||||
assert(n->cur[0] == type);
|
||||
// @TODO keep a stack with the count to make sure they do it right
|
||||
++n->nesting;
|
||||
n->cur += 5;
|
||||
return (int) len;
|
||||
}
|
||||
|
||||
static void nbt_end_list(nbt *n)
|
||||
{
|
||||
--n->nesting;
|
||||
}
|
||||
|
||||
// raw_block chunk is 16x256x16x4 = 2^(4+8+4+2) = 256KB
|
||||
//
|
||||
// if we want to process 64x64x256 at a time, that will be:
|
||||
// 4*4*256KB => 4MB per area in raw_block
|
||||
//
|
||||
// (plus we maybe need to decode adjacent regions)
|
||||
|
||||
|
||||
#ifdef FAST_CHUNK
|
||||
typedef fast_chunk parse_chunk;
|
||||
#else
|
||||
typedef chunk parse_chunk;
|
||||
#endif
|
||||
|
||||
static parse_chunk *minecraft_chunk_parse(unsigned char *data, size_t len)
|
||||
{
|
||||
char *s;
|
||||
parse_chunk *c = NULL;
|
||||
|
||||
nbt n_store, *n = &n_store;
|
||||
n->buffer_start = data;
|
||||
n->buffer_end = data + len;
|
||||
n->cur = n->buffer_start;
|
||||
n->nesting = 0;
|
||||
|
||||
nbt_begin_compound(n);
|
||||
while ((s = nbt_peek(n)) != NULL) {
|
||||
if (!strcmp(s, "Level")) {
|
||||
int *height;
|
||||
c = malloc(sizeof(*c));
|
||||
#ifdef FAST_CHUNK
|
||||
memset(c, 0, sizeof(*c));
|
||||
c->pointer_to_free = data;
|
||||
#else
|
||||
c->rb[15][15][255].block = 0;
|
||||
#endif
|
||||
c->max_y = 0;
|
||||
|
||||
nbt_begin_compound(n);
|
||||
while ((s = nbt_peek(n)) != NULL) {
|
||||
if (!strcmp(s, "xPos"))
|
||||
c->xpos = *(int *) nbt_get(n, TAG_Int, 0);
|
||||
else if (!strcmp(s, "zPos"))
|
||||
c->zpos = *(int *) nbt_get(n, TAG_Int, 0);
|
||||
else if (!strcmp(s, "Sections")) {
|
||||
int count = nbt_begin_list(n, TAG_Compound), i;
|
||||
if (count == -1) {
|
||||
// this not-a-list case happens in The End and I'm not sure
|
||||
// what it means... possibly one of those silly encodings
|
||||
// where it's not encoded as a list if there's only one?
|
||||
// not worth figuring out
|
||||
nbt_skip(n);
|
||||
count = -1;
|
||||
}
|
||||
for (i=0; i < count; ++i) {
|
||||
int yi, len;
|
||||
uint8 *light = NULL, *blocks = NULL, *data = NULL, *skylight = NULL;
|
||||
nbt_begin_compound_in_list(n);
|
||||
while ((s = nbt_peek(n)) != NULL) {
|
||||
if (!strcmp(s, "Y"))
|
||||
yi = * (uint8 *) nbt_get(n, TAG_Byte, 0);
|
||||
else if (!strcmp(s, "BlockLight")) {
|
||||
light = nbt_get(n, TAG_Byte_Array, &len);
|
||||
assert(len == 2048);
|
||||
} else if (!strcmp(s, "Blocks")) {
|
||||
blocks = nbt_get(n, TAG_Byte_Array, &len);
|
||||
assert(len == 4096);
|
||||
} else if (!strcmp(s, "Data")) {
|
||||
data = nbt_get(n, TAG_Byte_Array, &len);
|
||||
assert(len == 2048);
|
||||
} else if (!strcmp(s, "SkyLight")) {
|
||||
skylight = nbt_get(n, TAG_Byte_Array, &len);
|
||||
assert(len == 2048);
|
||||
}
|
||||
}
|
||||
nbt_end_compound(n);
|
||||
|
||||
assert(yi < 16);
|
||||
|
||||
#ifndef FAST_CHUNK
|
||||
|
||||
// clear data below current max_y
|
||||
{
|
||||
int x,z;
|
||||
while (c->max_y < yi*16) {
|
||||
for (x=0; x < 16; ++x)
|
||||
for (z=0; z < 16; ++z)
|
||||
c->rb[z][x][c->max_y].block = 0;
|
||||
++c->max_y;
|
||||
}
|
||||
}
|
||||
|
||||
// now assemble the data
|
||||
{
|
||||
int x,y,z, o2=0,o4=0;
|
||||
for (y=0; y < 16; ++y) {
|
||||
for (z=0; z < 16; ++z) {
|
||||
for (x=0; x < 16; x += 2) {
|
||||
raw_block *rb = &c->rb[15-z][x][y + yi*16]; // 15-z because switching to z-up will require flipping an axis
|
||||
rb[0].block = blocks[o4];
|
||||
rb[0].light = light[o2] & 15;
|
||||
rb[0].data = data[o2] & 15;
|
||||
rb[0].skylight = skylight[o2] & 15;
|
||||
|
||||
rb[256].block = blocks[o4+1];
|
||||
rb[256].light = light[o2] >> 4;
|
||||
rb[256].data = data[o2] >> 4;
|
||||
rb[256].skylight = skylight[o2] >> 4;
|
||||
|
||||
o2 += 1;
|
||||
o4 += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
c->max_y += 16;
|
||||
}
|
||||
#else
|
||||
c->blockdata[yi] = blocks;
|
||||
c->data [yi] = data;
|
||||
c->light [yi] = light;
|
||||
c->skylight [yi] = skylight;
|
||||
#endif
|
||||
}
|
||||
//nbt_end_list(n);
|
||||
} else if (!strcmp(s, "HeightMap")) {
|
||||
height = nbt_get(n, TAG_Int_Array, &len);
|
||||
assert(len == 256);
|
||||
} else
|
||||
nbt_skip(n);
|
||||
}
|
||||
nbt_end_compound(n);
|
||||
|
||||
} else
|
||||
nbt_skip(n);
|
||||
}
|
||||
nbt_end_compound(n);
|
||||
assert(n->cur == n->buffer_end);
|
||||
return c;
|
||||
}
|
||||
|
||||
#define MAX_DECODED_CHUNK_X 64
|
||||
#define MAX_DECODED_CHUNK_Z 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int cx,cz;
|
||||
fast_chunk *fc;
|
||||
int valid;
|
||||
} decoded_buffer;
|
||||
|
||||
static decoded_buffer decoded_buffers[MAX_DECODED_CHUNK_Z][MAX_DECODED_CHUNK_X];
|
||||
void lock_chunk_get_mutex(void);
|
||||
void unlock_chunk_get_mutex(void);
|
||||
|
||||
fast_chunk *get_decoded_fastchunk_uncached(int chunk_x, int chunk_z)
|
||||
{
|
||||
unsigned char *decoded;
|
||||
compressed_chunk *cc;
|
||||
int inlen;
|
||||
int len;
|
||||
fast_chunk *fc;
|
||||
|
||||
lock_chunk_get_mutex();
|
||||
cc = get_compressed_chunk(chunk_x, chunk_z);
|
||||
if (cc->len != 0)
|
||||
++cc->refcount;
|
||||
unlock_chunk_get_mutex();
|
||||
|
||||
if (cc->len == 0)
|
||||
return NULL;
|
||||
|
||||
assert(cc != NULL);
|
||||
|
||||
assert(cc->data[4] == 2);
|
||||
|
||||
inlen = nbt_parse_uint32(cc->data);
|
||||
decoded = stbi_zlib_decode_malloc_guesssize(cc->data+5, inlen, inlen*3, &len);
|
||||
assert(decoded != NULL);
|
||||
assert(len != 0);
|
||||
|
||||
lock_chunk_get_mutex();
|
||||
deref_compressed_chunk(cc);
|
||||
unlock_chunk_get_mutex();
|
||||
|
||||
#ifdef FAST_CHUNK
|
||||
fc = minecraft_chunk_parse(decoded, len);
|
||||
#else
|
||||
fc = NULL;
|
||||
#endif
|
||||
if (fc == NULL)
|
||||
free(decoded);
|
||||
return fc;
|
||||
}
|
||||
|
||||
|
||||
decoded_buffer *get_decoded_buffer(int chunk_x, int chunk_z)
|
||||
{
|
||||
decoded_buffer *db = &decoded_buffers[chunk_z&(MAX_DECODED_CHUNK_Z-1)][chunk_x&(MAX_DECODED_CHUNK_X-1)];
|
||||
if (db->valid) {
|
||||
if (db->cx == chunk_x && db->cz == chunk_z)
|
||||
return db;
|
||||
if (db->fc) {
|
||||
free(db->fc->pointer_to_free);
|
||||
free(db->fc);
|
||||
}
|
||||
}
|
||||
|
||||
db->cx = chunk_x;
|
||||
db->cz = chunk_z;
|
||||
db->valid = 1;
|
||||
db->fc = 0;
|
||||
|
||||
{
|
||||
db->fc = get_decoded_fastchunk_uncached(chunk_x, chunk_z);
|
||||
return db;
|
||||
}
|
||||
}
|
||||
|
||||
fast_chunk *get_decoded_fastchunk(int chunk_x, int chunk_z)
|
||||
{
|
||||
decoded_buffer *db = get_decoded_buffer(chunk_x, chunk_z);
|
||||
return db->fc;
|
||||
}
|
||||
|
||||
chunk *get_decoded_chunk_raw(int chunk_x, int chunk_z)
|
||||
{
|
||||
unsigned char *decoded;
|
||||
compressed_chunk *cc = get_compressed_chunk(chunk_x, chunk_z);
|
||||
assert(cc != NULL);
|
||||
if (cc->len == 0)
|
||||
return NULL;
|
||||
else {
|
||||
chunk *ch;
|
||||
int inlen = nbt_parse_uint32(cc->data);
|
||||
int len;
|
||||
assert(cc->data[4] == 2);
|
||||
decoded = stbi_zlib_decode_malloc_guesssize(cc->data+5, inlen, inlen*3, &len);
|
||||
assert(decoded != NULL);
|
||||
#ifdef FAST_CHUNK
|
||||
ch = NULL;
|
||||
#else
|
||||
ch = minecraft_chunk_parse(decoded, len);
|
||||
#endif
|
||||
free(decoded);
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
static chunk *decoded_chunks[MAX_DECODED_CHUNK_Z][MAX_DECODED_CHUNK_X];
|
||||
chunk *get_decoded_chunk(int chunk_x, int chunk_z)
|
||||
{
|
||||
chunk *c = decoded_chunks[chunk_z&(MAX_DECODED_CHUNK_Z-1)][chunk_x&(MAX_DECODED_CHUNK_X-1)];
|
||||
if (c && c->xpos == chunk_x && c->zpos == chunk_z)
|
||||
return c;
|
||||
if (c) free(c);
|
||||
c = get_decoded_chunk_raw(chunk_x, chunk_z);
|
||||
decoded_chunks[chunk_z&(MAX_DECODED_CHUNK_Z-1)][chunk_x&(MAX_DECODED_CHUNK_X-1)] = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
#if 0
|
||||
chunk *map[257][257];
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i,j;
|
||||
for (j= -32; j <= 32; ++j)
|
||||
for (i= -32; i <= 32; ++i)
|
||||
map[j+128][i+128] = get_decoded_chunk(i,j);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
41
tests/caveview/cave_parse.h
Normal file
41
tests/caveview/cave_parse.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef INCLUDE_CAVE_PARSE_H
|
||||
#define INCLUDE_CAVE_PARSE_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char block;
|
||||
unsigned char data;
|
||||
unsigned char light:4;
|
||||
unsigned char skylight:4;
|
||||
} raw_block;
|
||||
|
||||
// this is the old fully-decoded chunk
|
||||
typedef struct
|
||||
{
|
||||
int xpos, zpos, max_y;
|
||||
int height[16][16];
|
||||
raw_block rb[16][16][256]; // [z][x][y] which becomes [y][x][z] in stb
|
||||
} chunk;
|
||||
|
||||
chunk *get_decoded_chunk(int chunk_x, int chunk_z);
|
||||
|
||||
#define NUM_SEGMENTS 16
|
||||
typedef struct
|
||||
{
|
||||
int max_y, xpos, zpos;
|
||||
|
||||
unsigned char *blockdata[NUM_SEGMENTS];
|
||||
unsigned char *data[NUM_SEGMENTS];
|
||||
unsigned char *skylight[NUM_SEGMENTS];
|
||||
unsigned char *light[NUM_SEGMENTS];
|
||||
|
||||
void *pointer_to_free;
|
||||
|
||||
int refcount; // this allows multi-threaded building without wrapping in ANOTHER struct
|
||||
} fast_chunk;
|
||||
|
||||
fast_chunk *get_decoded_fastchunk(int chunk_x, int chunk_z); // cache, never call free()
|
||||
|
||||
fast_chunk *get_decoded_fastchunk_uncached(int chunk_x, int chunk_z);
|
||||
|
||||
#endif
|
157
tests/caveview/caveview.dsp
Normal file
157
tests/caveview/caveview.dsp
Normal file
@ -0,0 +1,157 @@
|
||||
# Microsoft Developer Studio Project File - Name="caveview" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Application" 0x0101
|
||||
|
||||
CFG=caveview - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "caveview.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "caveview.mak" CFG="caveview - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "caveview - Win32 Release" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "caveview - Win32 Debug" (based on "Win32 (x86) Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "caveview - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /WX /GX /Zd /O2 /I "../.." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl2.lib opengl32.lib glu32.lib winmm.lib sdl2_mixer.lib advapi32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Release/caveview.exe"
|
||||
# SUBTRACT LINK32 /map
|
||||
|
||||
!ELSEIF "$(CFG)" == "caveview - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /WX /Gm /GX /Zi /Od /I "../.." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl2.lib opengl32.lib glu32.lib winmm.lib sdl2_mixer.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "caveview - Win32 Release"
|
||||
# Name "caveview - Win32 Debug"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\cave_parse.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\cave_parse.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\game.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\game.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\glext.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\glext_list.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\main.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\render.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\win32\SDL_windows_main.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stb.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stb_easy_font.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stb_gl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stb_glprog.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stb_image.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stb_image_write.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stb_voxel_render.h
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
29
tests/caveview/caveview.dsw
Normal file
29
tests/caveview/caveview.dsw
Normal file
@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "caveview"=.\caveview.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
354
tests/caveview/game.c
Normal file
354
tests/caveview/game.c
Normal file
@ -0,0 +1,354 @@
|
||||
#include <windows.h>
|
||||
#include "game.h"
|
||||
#include "stb.h"
|
||||
|
||||
#include "sdl.h"
|
||||
#include "SDL_opengl.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#define STB_GL_IMPLEMENTATION
|
||||
#include "stb_gl.h"
|
||||
|
||||
#define STB_GLPROG_IMPLEMENTATION
|
||||
#define STB_GLPROG_ARB_DEFINE_EXTENSIONS
|
||||
#include "stb_glprog.h"
|
||||
|
||||
#include "stb_easy_font.h"
|
||||
|
||||
char *game_name = "caveview";
|
||||
|
||||
// assume only a single texture with all sprites
|
||||
float texture_s_scale;
|
||||
float texture_t_scale;
|
||||
GLuint interface_tex, logo_tex;
|
||||
|
||||
extern int screen_x, screen_y; // main.c
|
||||
|
||||
int tex_w, tex_h;
|
||||
void *tex_data;
|
||||
|
||||
GLuint load_texture(char *filename, int keep)
|
||||
{
|
||||
GLuint tex;
|
||||
tex_data = stbi_load(filename, &tex_w, &tex_h, NULL, 4);
|
||||
if (tex_data == NULL) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
|
||||
game_name,
|
||||
"Couldn't open image file.",
|
||||
NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
if (!keep) {
|
||||
free(tex_data);
|
||||
tex_data = NULL;
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
static void init_graphics(void)
|
||||
{
|
||||
//logo_tex = load_texture("sss_logo.png",0);
|
||||
//interface_tex = load_texture("game_art.png",1);
|
||||
texture_s_scale = 1.0f / tex_w;
|
||||
texture_t_scale = 1.0f / tex_h;
|
||||
}
|
||||
|
||||
void print_string(float x, float y, char *text, float r, float g, float b)
|
||||
{
|
||||
static char buffer[99999];
|
||||
int num_quads;
|
||||
|
||||
num_quads = stb_easy_font_print(x, y, text, NULL, buffer, sizeof(buffer));
|
||||
|
||||
glColor3f(r,g,b);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 16, buffer);
|
||||
glDrawArrays(GL_QUADS, 0, num_quads*4);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
float text_color[3];
|
||||
float pos_x = 10;
|
||||
float pos_y = 10;
|
||||
|
||||
void print(char *text, ...)
|
||||
{
|
||||
char buffer[999];
|
||||
va_list va;
|
||||
va_start(va, text);
|
||||
vsprintf(buffer, text, va);
|
||||
va_end(va);
|
||||
print_string(pos_x, pos_y, buffer, text_color[0], text_color[1], text_color[2]);
|
||||
pos_y += 10;
|
||||
}
|
||||
|
||||
// mouse offsetting 'pixel to virtual'
|
||||
float xs_p2v, ys_p2v;// xoff_p2v, yoff_p2v;
|
||||
|
||||
// viewport offseting 'virtual to pixel'
|
||||
float xs_v2p, ys_v2p, xoff_v2p, yoff_v2p;
|
||||
|
||||
float camang[3], camloc[3] = { 0,0,75 };
|
||||
float player_zoom = 1.0;
|
||||
int third_person;
|
||||
float rotate_view = 0.0;
|
||||
|
||||
#define REVERSE_DEPTH
|
||||
|
||||
|
||||
void init_game(void)
|
||||
{
|
||||
init_graphics();
|
||||
}
|
||||
|
||||
void render_caves(float pos[3]);
|
||||
|
||||
void camera_to_worldspace(float world[3], float cam_x, float cam_y, float cam_z)
|
||||
{
|
||||
float vec[3] = { cam_x, cam_y, cam_z };
|
||||
float t[3];
|
||||
float s,c;
|
||||
s = sin(camang[0]*3.141592/180);
|
||||
c = cos(camang[0]*3.141592/180);
|
||||
|
||||
t[0] = vec[0];
|
||||
t[1] = c*vec[1] - s*vec[2];
|
||||
t[2] = s*vec[1] + c*vec[2];
|
||||
|
||||
s = sin(camang[2]*3.141592/180);
|
||||
c = cos(camang[2]*3.141592/180);
|
||||
world[0] = c*t[0] - s*t[1];
|
||||
world[1] = s*t[0] + c*t[1];
|
||||
world[2] = t[2];
|
||||
}
|
||||
|
||||
// camera worldspace velocity
|
||||
float cam_vel[3];
|
||||
|
||||
int controls;
|
||||
|
||||
#define MAX_VEL 150 // blocks per second
|
||||
#define ACCEL 6
|
||||
#define DECEL 3
|
||||
|
||||
#define STATIC_FRICTION DECEL
|
||||
#define EFFECTIVE_ACCEL (ACCEL+DECEL)
|
||||
|
||||
// dynamic friction:
|
||||
//
|
||||
// if going at MAX_VEL, ACCEL and friction must cancel
|
||||
// EFFECTIVE_ACCEL = DECEL + DYNAMIC_FRIC*MAX_VEL
|
||||
#define DYNAMIC_FRICTION (ACCEL/(float)MAX_VEL)
|
||||
|
||||
float view_x_vel = 0;
|
||||
float view_z_vel = 0;
|
||||
float pending_view_x;
|
||||
float pending_view_z;
|
||||
float pending_view_x;
|
||||
float pending_view_z;
|
||||
|
||||
void process_tick_raw(float dt)
|
||||
{
|
||||
int i;
|
||||
float thrust[3] = { 0,0,0 };
|
||||
float world_thrust[3];
|
||||
|
||||
// choose direction to apply thrust
|
||||
|
||||
thrust[0] = (controls & 3)== 1 ? EFFECTIVE_ACCEL : (controls & 3)== 2 ? -EFFECTIVE_ACCEL : 0;
|
||||
thrust[1] = (controls & 12)== 4 ? EFFECTIVE_ACCEL : (controls & 12)== 8 ? -EFFECTIVE_ACCEL : 0;
|
||||
thrust[2] = (controls & 48)==16 ? EFFECTIVE_ACCEL : (controls & 48)==32 ? -EFFECTIVE_ACCEL : 0;
|
||||
|
||||
// @TODO clamp thrust[0] & thrust[1] vector length to EFFECTIVE_ACCEL
|
||||
|
||||
camera_to_worldspace(world_thrust, thrust[0], thrust[1], 0);
|
||||
world_thrust[2] += thrust[2];
|
||||
|
||||
for (i=0; i < 3; ++i) {
|
||||
float acc = world_thrust[i];
|
||||
cam_vel[i] += acc*dt;
|
||||
}
|
||||
|
||||
if (cam_vel[0] || cam_vel[1] || cam_vel[2])
|
||||
{
|
||||
float vel = sqrt(cam_vel[0]*cam_vel[0] + cam_vel[1]*cam_vel[1] + cam_vel[2]*cam_vel[2]);
|
||||
float newvel = vel;
|
||||
float dec = STATIC_FRICTION + DYNAMIC_FRICTION*vel;
|
||||
newvel = vel - dec*dt;
|
||||
if (newvel < 0)
|
||||
newvel = 0;
|
||||
cam_vel[0] *= newvel/vel;
|
||||
cam_vel[1] *= newvel/vel;
|
||||
cam_vel[2] *= newvel/vel;
|
||||
}
|
||||
|
||||
camloc[0] += cam_vel[0] * dt;
|
||||
camloc[1] += cam_vel[1] * dt;
|
||||
camloc[2] += cam_vel[2] * dt;
|
||||
|
||||
view_x_vel *= pow(0.75, dt);
|
||||
view_z_vel *= pow(0.75, dt);
|
||||
|
||||
view_x_vel += (pending_view_x - view_x_vel)*dt*60;
|
||||
view_z_vel += (pending_view_z - view_z_vel)*dt*60;
|
||||
|
||||
pending_view_x -= view_x_vel * dt;
|
||||
pending_view_z -= view_z_vel * dt;
|
||||
camang[0] += view_x_vel * dt;
|
||||
camang[2] += view_z_vel * dt;
|
||||
camang[0] = stb_clamp(camang[0], -90, 90);
|
||||
camang[2] = fmod(camang[2], 360);
|
||||
}
|
||||
|
||||
void process_tick(float dt)
|
||||
{
|
||||
while (dt > 1.0/60) {
|
||||
process_tick_raw(1.0/60);
|
||||
dt -= 1.0/60;
|
||||
}
|
||||
process_tick_raw(dt);
|
||||
}
|
||||
|
||||
void update_view(float dx, float dy)
|
||||
{
|
||||
// hard-coded mouse sensitivity, not resolution independent?
|
||||
pending_view_z -= dx*300;
|
||||
pending_view_x -= dy*700;
|
||||
}
|
||||
|
||||
extern int screen_x, screen_y;
|
||||
extern int is_synchronous_debug;
|
||||
float render_time;
|
||||
|
||||
extern int chunk_locations, chunks_considered, chunks_in_frustum;
|
||||
extern int quads_considered, quads_rendered;
|
||||
extern int chunk_storage_rendered, chunk_storage_considered, chunk_storage_total;
|
||||
extern int view_dist_in_chunks;
|
||||
extern int num_threads_active, num_meshes_started, num_meshes_uploaded;
|
||||
extern float chunk_server_activity;
|
||||
|
||||
static Uint64 start_time, end_time; // render time
|
||||
|
||||
float chunk_server_status[32];
|
||||
int chunk_server_pos;
|
||||
|
||||
void draw_stats(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
static Uint64 last_frame_time;
|
||||
Uint64 cur_time = SDL_GetPerformanceCounter();
|
||||
float chunk_server=0;
|
||||
float frame_time = (cur_time - last_frame_time) / (float) SDL_GetPerformanceFrequency();
|
||||
last_frame_time = cur_time;
|
||||
|
||||
chunk_server_status[chunk_server_pos] = chunk_server_activity;
|
||||
chunk_server_pos = (chunk_server_pos+1) %32;
|
||||
|
||||
for (i=0; i < 32; ++i)
|
||||
chunk_server += chunk_server_status[i] / 32.0;
|
||||
|
||||
stb_easy_font_spacing(-0.75);
|
||||
pos_y = 10;
|
||||
text_color[0] = text_color[1] = text_color[2] = 1.0f;
|
||||
print("Frame time: %6.2fms, CPU frame render time: %5.2fms", frame_time*1000, render_time*1000);
|
||||
print("Tris: %4.1fM drawn of %4.1fM in range", 2*quads_rendered/1000000.0f, 2*quads_considered/1000000.0f);
|
||||
print("Vbuf storage: %dMB in frustum of %dMB in range of %dMB in cache", chunk_storage_rendered>>20, chunk_storage_considered>>20, chunk_storage_total>>20);
|
||||
print("Num mesh builds started this frame: %d; num uploaded this frame: %d\n", num_meshes_started, num_meshes_uploaded);
|
||||
print("QChunks: %3d in frustum of %3d valid of %3d in range", chunks_in_frustum, chunks_considered, chunk_locations);
|
||||
print("Mesh worker threads active: %d", num_threads_active);
|
||||
print("View distance: %d blocks", view_dist_in_chunks*16);
|
||||
print("%s", glGetString(GL_RENDERER));
|
||||
|
||||
if (is_synchronous_debug) {
|
||||
text_color[0] = 1.0;
|
||||
text_color[1] = 0.5;
|
||||
text_color[2] = 0.5;
|
||||
print("SLOWNESS: Synchronous debug output is enabled!");
|
||||
}
|
||||
}
|
||||
|
||||
void draw_main(void)
|
||||
{
|
||||
glEnable(GL_CULL_FACE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
#ifdef REVERSE_DEPTH
|
||||
glDepthFunc(GL_GREATER);
|
||||
glClearDepth(0);
|
||||
#else
|
||||
glDepthFunc(GL_LESS);
|
||||
glClearDepth(1);
|
||||
#endif
|
||||
glDepthMask(GL_TRUE);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glClearColor(0.6,0.7,0.9,0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glColor3f(1,1,1);
|
||||
glFrontFace(GL_CW);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
#ifdef REVERSE_DEPTH
|
||||
stbgl_Perspective(player_zoom, 90, 70, 3000, 1.0/16);
|
||||
#else
|
||||
stbgl_Perspective(player_zoom, 90, 70, 1.0/16, 3000);
|
||||
#endif
|
||||
|
||||
// now compute where the camera should be
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
stbgl_initCamera_zup_facing_y();
|
||||
|
||||
//glTranslatef(0,150,-5);
|
||||
// position the camera and render it
|
||||
|
||||
if (third_person) {
|
||||
glTranslatef(0,2.5,0);
|
||||
glRotatef(-camang[0],1,0,0);
|
||||
|
||||
glTranslatef(0,2,0);
|
||||
glRotatef(-camang[2]-rotate_view,0,0,1);
|
||||
|
||||
//glTranslatef(0,0,1);
|
||||
//glTranslatef(0,0,-1);
|
||||
} else {
|
||||
glRotatef(-camang[0],1,0,0);
|
||||
glRotatef(-camang[2],0,0,1);
|
||||
}
|
||||
|
||||
glTranslatef(-camloc[0], -camloc[1], -camloc[2]);
|
||||
|
||||
start_time = SDL_GetPerformanceCounter();
|
||||
render_caves(camloc);
|
||||
end_time = SDL_GetPerformanceCounter();
|
||||
|
||||
render_time = (end_time - start_time) / (float) SDL_GetPerformanceFrequency();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0,screen_x/2,screen_y/2,0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
draw_stats();
|
||||
}
|
43
tests/caveview/game.h
Normal file
43
tests/caveview/game.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef INCLUDED_GAME_H
|
||||
#define INCLUDED_GAME_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
typedef unsigned int uint32;
|
||||
typedef signed int int32;
|
||||
typedef unsigned short uint16;
|
||||
typedef signed short int16;
|
||||
typedef unsigned char uint8 ;
|
||||
typedef signed char int8 ;
|
||||
|
||||
|
||||
#pragma warning(disable:4244; disable:4305; disable:4018)
|
||||
|
||||
// virtual screen size
|
||||
#define SIZE_X 480
|
||||
#define SIZE_Y 360
|
||||
|
||||
// main.c
|
||||
extern void error(char *s);
|
||||
extern void ods(char *fmt, ...);
|
||||
|
||||
|
||||
// game.c
|
||||
extern void init_game(void);
|
||||
extern void draw_main(void);
|
||||
extern void process_tick(float dt);
|
||||
|
||||
|
||||
#define BUTTON_MAX 15
|
||||
typedef struct
|
||||
{
|
||||
int id;
|
||||
uint8 buttons[BUTTON_MAX];
|
||||
float axes[4];
|
||||
float triggers[2];
|
||||
} gamepad;
|
||||
|
||||
extern gamepad pads[4];
|
||||
|
||||
|
||||
#endif
|
11124
tests/caveview/glext.h
Normal file
11124
tests/caveview/glext.h
Normal file
File diff suppressed because it is too large
Load Diff
54
tests/caveview/glext_list.h
Normal file
54
tests/caveview/glext_list.h
Normal file
@ -0,0 +1,54 @@
|
||||
GLARB(ActiveTexture,ACTIVETEXTURE)
|
||||
GLARB(ClientActiveTexture,CLIENTACTIVETEXTURE)
|
||||
GLARB(MultiTexCoord2f,MULTITEXCOORD2F)
|
||||
GLEXT(TexImage3D,TEXIMAGE3D)
|
||||
GLEXT(TexSubImage3D,TEXSUBIMAGE3D)
|
||||
GLEXT(GenerateMipmap,GENERATEMIPMAP)
|
||||
GLARB(DebugMessageCallback,DEBUGMESSAGECALLBACK)
|
||||
|
||||
GLARB(DeleteObject,DELETEOBJECT)
|
||||
GLARB(CreateProgramObject,CREATEPROGRAMOBJECT)
|
||||
GLARB(UseProgramObject,USEPROGRAMOBJECT)
|
||||
GLARB(CreateShaderObject,CREATESHADEROBJECT)
|
||||
GLARB(ShaderSource,SHADERSOURCE)
|
||||
GLARB(CompileShader,COMPILESHADER)
|
||||
GLARB(GetInfoLog,GETINFOLOG)
|
||||
GLARB(AttachObject,ATTACHOBJECT)
|
||||
GLARB(LinkProgram,LINKPROGRAM)
|
||||
GLARB(GetObjectParameteriv,GETOBJECTPARAMETERIV)
|
||||
GLARB(GetUniformLocation,GETUNIFORMLOCATION)
|
||||
GLARB(Uniform1i,UNIFORM1I)
|
||||
GLARB(Uniform1f,UNIFORM1F)
|
||||
GLARB(Uniform4f,UNIFORM4F)
|
||||
GLARB(Uniform2fv,UNIFORM2FV)
|
||||
GLARB(Uniform3fv,UNIFORM3FV)
|
||||
GLARB(Uniform4fv,UNIFORM4FV)
|
||||
GLARB(VertexAttribPointer,VERTEXATTRIBPOINTER)
|
||||
GLCORE(VertexAttribIPointer,VERTEXATTRIBIPOINTER)
|
||||
GLARB(EnableVertexAttribArray,ENABLEVERTEXATTRIBARRAY)
|
||||
GLARB(DisableVertexAttribArray,DISABLEVERTEXATTRIBARRAY)
|
||||
|
||||
GLEXT(BindFramebuffer,BINDFRAMEBUFFER)
|
||||
GLEXT(DeleteFramebuffers,DELETEFRAMEBUFFERS)
|
||||
GLEXT(GenFramebuffers,GENFRAMEBUFFERS)
|
||||
GLEXT(CheckFramebufferStatus,CHECKFRAMEBUFFERSTATUS)
|
||||
GLEXT(FramebufferTexture2D,FRAMEBUFFERTEXTURE2D)
|
||||
GLEXT(BindRenderBuffer,BINDRENDERBUFFER)
|
||||
GLEXT(RenderbufferStorage,RENDERBUFFERSTORAGE)
|
||||
GLEXT(GenRenderbuffers,GENRENDERBUFFERS)
|
||||
GLEXT(BindRenderbuffer,BINDRENDERBUFFER)
|
||||
GLEXT(FramebufferRenderbuffer,FRAMEBUFFERRENDERBUFFER)
|
||||
GLEXT(GenerateMipmap,GENERATEMIPMAP)
|
||||
|
||||
GLARB(BindBuffer ,BINDBUFFER,)
|
||||
GLARB(GenBuffers ,GENBUFFERS )
|
||||
GLARB(DeleteBuffers,DELETEBUFFERS)
|
||||
GLARB(BufferData ,BUFFERDATA )
|
||||
GLARB(BufferSubData,BUFFERSUBDATA)
|
||||
GLARB(MapBuffer ,MAPBUFFER )
|
||||
GLARB(UnmapBuffer ,UNMAPBUFFER )
|
||||
GLARB(TexBuffer ,TEXBUFFER )
|
||||
|
||||
GLEXT(NamedBufferStorage,NAMEDBUFFERSTORAGE)
|
||||
GLE(BufferStorage,BUFFERSTORAGE)
|
||||
GLE(GetStringi,GETSTRINGI)
|
354
tests/caveview/main.c
Normal file
354
tests/caveview/main.c
Normal file
@ -0,0 +1,354 @@
|
||||
#pragma warning(disable:4244; disable:4305; disable:4018)
|
||||
|
||||
#define _WIN32_WINNT 0x400
|
||||
|
||||
#include "sdl.h"
|
||||
#include "sdl_mixer.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "game.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define STB_GLEXT_DEFINE "glext_list.h"
|
||||
#include "stb_gl.h"
|
||||
|
||||
#define STB_DEFINE
|
||||
#include "stb.h"
|
||||
|
||||
#define SCALE 2
|
||||
|
||||
void error(char *s)
|
||||
{
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", s, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void ods(char *fmt, ...)
|
||||
{
|
||||
char buffer[1000];
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vsprintf(buffer, fmt, va);
|
||||
va_end(va);
|
||||
SDL_Log("%s", buffer);
|
||||
}
|
||||
|
||||
#define TICKS_PER_SECOND 60
|
||||
|
||||
static SDL_Window *window;
|
||||
|
||||
extern void init_game(void);
|
||||
extern void draw_main(void);
|
||||
extern void process_tick(float dt);
|
||||
extern void editor_init(void);
|
||||
|
||||
void draw(void)
|
||||
{
|
||||
draw_main();
|
||||
SDL_GL_SwapWindow(window);
|
||||
}
|
||||
|
||||
|
||||
static int initialized=0;
|
||||
static float last_dt;
|
||||
|
||||
int screen_x,screen_y;
|
||||
|
||||
float carried_dt = 0;
|
||||
#define TICKRATE 60
|
||||
|
||||
|
||||
int raw_level_time;
|
||||
extern void init_game(void);
|
||||
extern void draw_main(void);
|
||||
|
||||
float global_timer;
|
||||
|
||||
int loopmode(float dt, int real, int in_client)
|
||||
{
|
||||
float actual_dt = dt;
|
||||
|
||||
float jump_timer = dt;
|
||||
|
||||
if (!initialized) return 0;
|
||||
|
||||
if (!real)
|
||||
return 0;
|
||||
|
||||
// don't allow more than 6 frames to update at a time
|
||||
if (dt > 0.075) dt = 0.075;
|
||||
|
||||
global_timer += dt;
|
||||
|
||||
carried_dt += dt;
|
||||
while (carried_dt > 1.0/TICKRATE) {
|
||||
//update_input();
|
||||
// if the player is dead, stop the sim
|
||||
carried_dt -= 1.0/TICKRATE;
|
||||
}
|
||||
|
||||
process_tick(dt);
|
||||
draw();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int quit;
|
||||
|
||||
//int winproc(void *data, stbwingraph_event *e)
|
||||
|
||||
extern int editor_scale;
|
||||
extern void editor_key(enum stbte_action act);
|
||||
extern int controls;
|
||||
|
||||
void active_control_set(int key)
|
||||
{
|
||||
controls |= 1 << key;
|
||||
}
|
||||
|
||||
void active_control_clear(int key)
|
||||
{
|
||||
controls &= ~(1 << key);
|
||||
}
|
||||
|
||||
extern void update_view(float dx, float dy);
|
||||
|
||||
void process_sdl_mouse(SDL_Event *e)
|
||||
{
|
||||
update_view((float) e->motion.xrel / screen_x, (float) e->motion.yrel / screen_y);
|
||||
}
|
||||
|
||||
void process_event(SDL_Event *e)
|
||||
{
|
||||
switch (e->type) {
|
||||
case SDL_MOUSEMOTION:
|
||||
process_sdl_mouse(e);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEWHEEL:
|
||||
//stbte_mouse_sdl(edit_map, e, 1.0f/editor_scale,1.0f/editor_scale,0,0);
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
quit = 1;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (e->window.event) {
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
screen_x = e->window.data1;
|
||||
screen_y = e->window.data2;
|
||||
loopmode(0,1,0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_TEXTINPUT:
|
||||
switch(e->text.text[0]) {
|
||||
#if 0
|
||||
case 27: {
|
||||
#if 0
|
||||
int result;
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
if (MessageBox(e->handle, "Exit CLTT?", "CLTT", MB_OKCANCEL) == IDOK);
|
||||
#endif
|
||||
{
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
//SDL_ShowCursor(SDL_DISABLE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_KEYDOWN: {
|
||||
int k = e->key.keysym.sym;
|
||||
int s = e->key.keysym.scancode;
|
||||
SDL_Keymod mod;
|
||||
mod = SDL_GetModState();
|
||||
if (k == SDLK_ESCAPE) {
|
||||
#ifndef DO_EDITOR
|
||||
quit = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (s == SDL_SCANCODE_D) active_control_set(0);
|
||||
if (s == SDL_SCANCODE_A) active_control_set(1);
|
||||
if (s == SDL_SCANCODE_W) active_control_set(2);
|
||||
if (s == SDL_SCANCODE_S) active_control_set(3);
|
||||
if (k == SDLK_SPACE) active_control_set(4);
|
||||
if (s == SDL_SCANCODE_LCTRL) active_control_set(5);
|
||||
if (s == SDL_SCANCODE_S) active_control_set(6);
|
||||
if (s == SDL_SCANCODE_D) active_control_set(7);
|
||||
|
||||
#if 0
|
||||
if (game_mode == GAME_editor) {
|
||||
switch (k) {
|
||||
case SDLK_RIGHT: editor_key(STBTE_scroll_right); break;
|
||||
case SDLK_LEFT : editor_key(STBTE_scroll_left ); break;
|
||||
case SDLK_UP : editor_key(STBTE_scroll_up ); break;
|
||||
case SDLK_DOWN : editor_key(STBTE_scroll_down ); break;
|
||||
}
|
||||
switch (s) {
|
||||
case SDL_SCANCODE_S: editor_key(STBTE_tool_select); break;
|
||||
case SDL_SCANCODE_B: editor_key(STBTE_tool_brush ); break;
|
||||
case SDL_SCANCODE_E: editor_key(STBTE_tool_erase ); break;
|
||||
case SDL_SCANCODE_R: editor_key(STBTE_tool_rectangle ); break;
|
||||
case SDL_SCANCODE_I: editor_key(STBTE_tool_eyedropper); break;
|
||||
case SDL_SCANCODE_L: editor_key(STBTE_tool_link); break;
|
||||
case SDL_SCANCODE_G: editor_key(STBTE_act_toggle_grid); break;
|
||||
}
|
||||
if ((e->key.keysym.mod & KMOD_CTRL) && !(e->key.keysym.mod & ~KMOD_CTRL)) {
|
||||
switch (s) {
|
||||
case SDL_SCANCODE_X: editor_key(STBTE_act_cut ); break;
|
||||
case SDL_SCANCODE_C: editor_key(STBTE_act_copy ); break;
|
||||
case SDL_SCANCODE_V: editor_key(STBTE_act_paste); break;
|
||||
case SDL_SCANCODE_Z: editor_key(STBTE_act_undo ); break;
|
||||
case SDL_SCANCODE_Y: editor_key(STBTE_act_redo ); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case SDL_KEYUP: {
|
||||
int k = e->key.keysym.sym;
|
||||
int s = e->key.keysym.scancode;
|
||||
if (s == SDL_SCANCODE_D) active_control_clear(0);
|
||||
if (s == SDL_SCANCODE_A) active_control_clear(1);
|
||||
if (s == SDL_SCANCODE_W) active_control_clear(2);
|
||||
if (s == SDL_SCANCODE_S) active_control_clear(3);
|
||||
if (k == SDLK_SPACE) active_control_clear(4);
|
||||
if (s == SDL_SCANCODE_LCTRL) active_control_clear(5);
|
||||
if (s == SDL_SCANCODE_S) active_control_clear(6);
|
||||
if (s == SDL_SCANCODE_D) active_control_clear(7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_GLContext *context;
|
||||
|
||||
static float getTimestep(float minimum_time)
|
||||
{
|
||||
float elapsedTime;
|
||||
double thisTime;
|
||||
static double lastTime = -1;
|
||||
|
||||
if (lastTime == -1)
|
||||
lastTime = SDL_GetTicks() / 1000.0 - minimum_time;
|
||||
|
||||
for(;;) {
|
||||
thisTime = SDL_GetTicks() / 1000.0;
|
||||
elapsedTime = (float) (thisTime - lastTime);
|
||||
if (elapsedTime >= minimum_time) {
|
||||
lastTime = thisTime;
|
||||
return elapsedTime;
|
||||
}
|
||||
// @TODO: compute correct delay
|
||||
SDL_Delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
void APIENTRY gl_debug(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *param)
|
||||
{
|
||||
#if 0
|
||||
if (severity == GL_DEBUG_SEVERITY_LOW_ARB)
|
||||
return;
|
||||
#endif
|
||||
ods("%s\n", message);
|
||||
}
|
||||
|
||||
extern void do_music(int16 *stream, int samples);
|
||||
|
||||
extern void foo(void);
|
||||
|
||||
void render_init(void);
|
||||
|
||||
int is_synchronous_debug;
|
||||
void enable_synchronous(void)
|
||||
{
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
||||
is_synchronous_debug = 1;
|
||||
}
|
||||
|
||||
void prepare_threads(void);
|
||||
|
||||
//void stbwingraph_main(void)
|
||||
int SDL_main(int argc, char **argv)
|
||||
{
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
prepare_threads();
|
||||
|
||||
Mix_Init(0);
|
||||
Mix_OpenAudio(48000, AUDIO_S16SYS, 2, 1024); // 1024 bytes = 256 samples =
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE , 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE , 8);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||
|
||||
#ifdef GL_DEBUG
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
|
||||
#endif
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
|
||||
|
||||
screen_x = 1920;
|
||||
screen_y = 1080;
|
||||
|
||||
window = SDL_CreateWindow("caveview", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||
screen_x, screen_y,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
|
||||
);
|
||||
if (!window) error("Couldn't create window");
|
||||
|
||||
context = SDL_GL_CreateContext(window);
|
||||
if (!context) error("Couldn't create context");
|
||||
|
||||
SDL_GL_MakeCurrent(window, context); // is this true by default?
|
||||
|
||||
// if (!IsDebuggerPresent())
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
|
||||
stbgl_initExtensions();
|
||||
|
||||
#ifdef GL_DEBUG
|
||||
if (glDebugMessageCallbackARB) {
|
||||
glDebugMessageCallbackARB(gl_debug, NULL);
|
||||
|
||||
enable_synchronous();
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_GL_SetSwapInterval(0); // only when profiling
|
||||
|
||||
render_init();
|
||||
init_game();
|
||||
//editor_init();
|
||||
initialized = 1;
|
||||
|
||||
while (!quit) {
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e))
|
||||
process_event(&e);
|
||||
|
||||
loopmode(getTimestep(0.0166f/8), 1, 1);
|
||||
quit=quit;
|
||||
}
|
||||
//music_end();
|
||||
|
||||
return 0;
|
||||
}
|
1745
tests/caveview/render.c
Normal file
1745
tests/caveview/render.c
Normal file
File diff suppressed because it is too large
Load Diff
1103
tests/caveview/stb_gl.h
Normal file
1103
tests/caveview/stb_gl.h
Normal file
File diff suppressed because it is too large
Load Diff
504
tests/caveview/stb_glprog.h
Normal file
504
tests/caveview/stb_glprog.h
Normal file
@ -0,0 +1,504 @@
|
||||
// stb_glprog v0.02 public domain functions to reduce GLSL boilerplate
|
||||
// http://nothings.org/stb/stb_glprog.h especially with GL1 + ARB extensions
|
||||
//
|
||||
// Following defines *before* including have following effects:
|
||||
//
|
||||
// STB_GLPROG_IMPLEMENTATION
|
||||
// creates the implementation
|
||||
//
|
||||
// STB_GLPROG_STATIC
|
||||
// forces the implementation to be static (private to file that creates it)
|
||||
//
|
||||
// STB_GLPROG_ARB
|
||||
// uses ARB extension names for GLSL functions and enumerants instead of core names
|
||||
//
|
||||
// STB_GLPROG_ARB_DEFINE_EXTENSIONS
|
||||
// instantiates function pointers needed, static to implementing file
|
||||
// to avoid collisions (but will collide if implementing file also
|
||||
// defines any; best to isolate this to its own file in this case).
|
||||
// This will try to automatically #include glext.h, but if it's not
|
||||
// in the default include directories you'll need to include it
|
||||
// yourself and define the next macro.
|
||||
//
|
||||
// STB_GLPROG_SUPPRESS_GLEXT_INCLUDE
|
||||
// disables the automatic #include of glext.h which is normally
|
||||
// forced by STB_GLPROG_ARB_DEFINE_EXTENSIONS
|
||||
//
|
||||
// So, e.g., sample usage on an old Windows compiler:
|
||||
//
|
||||
// #define STB_GLPROG_IMPLEMENTATION
|
||||
// #define STB_GLPROG_ARB_DEFINE_EXTENSIONS
|
||||
// #include <windows.h>
|
||||
// #include "gl/gl.h"
|
||||
// #include "stb_glprog.h"
|
||||
//
|
||||
// Note though that the header-file version of this (when you don't define
|
||||
// STB_GLPROG_IMPLEMENTATION) still uses GLint and such, so you basically
|
||||
// can only include it in places where you're already including GL, especially
|
||||
// on Windows where including "gl.h" requires (some of) "windows.h".
|
||||
//
|
||||
// See following comment blocks for function documentation.
|
||||
//
|
||||
// Version history:
|
||||
// 2013-12-08 v0.02 slightly simplified API and reduced GL resource usage (@rygorous)
|
||||
// 2013-12-08 v0.01 initial release
|
||||
|
||||
|
||||
// header file section starts here
|
||||
#if !defined(INCLUDE_STB_GLPROG_H)
|
||||
#define INCLUDE_STB_GLPROG_H
|
||||
|
||||
#ifndef STB_GLPROG_STATIC
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////// SHADER CREATION
|
||||
|
||||
|
||||
/// EASY API
|
||||
|
||||
extern GLuint stbgl_create_program(char const **vertex_source, char const **frag_source, char const **binds, char *error, int error_buflen);
|
||||
// This function returns a compiled program or 0 if there's an error.
|
||||
// To free the created program, call stbgl_delete_program.
|
||||
//
|
||||
// stbgl_create_program(
|
||||
// char **vertex_source, // NULL or one or more strings with the vertex shader source, with a final NULL
|
||||
// char **frag_source, // NULL or one or more strings with the fragment shader source, with a final NULL
|
||||
// char **binds, // NULL or zero or more strings with attribute bind names, with a final NULL
|
||||
// char *error, // output location where compile error message is placed
|
||||
// int error_buflen) // length of error output buffer
|
||||
//
|
||||
// Returns a GLuint with the GL program object handle.
|
||||
//
|
||||
// If an individual bind string is "", no name is bound to that slot (this
|
||||
// allows you to create binds that aren't continuous integers starting at 0).
|
||||
//
|
||||
// If the vertex shader is NULL, then fixed-function vertex pipeline
|
||||
// is used, if that's legal in your version of GL.
|
||||
//
|
||||
// If the fragment shader is NULL, then fixed-function fragment pipeline
|
||||
// is used, if that's legal in your version of GL.
|
||||
|
||||
extern void stgbl_delete_program(GLuint program);
|
||||
// deletes a program created by stbgl_create_program or stbgl_link_program
|
||||
|
||||
|
||||
/// FLEXIBLE API
|
||||
|
||||
extern GLuint stbgl_compile_shader(GLenum type, char const **sources, int num_sources, char *error, int error_buflen);
|
||||
// compiles a shader. returns the shader on success or 0 on failure.
|
||||
//
|
||||
// type either: GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
|
||||
// or GL_VERTEX_SHADER_ARB or GL_FRAGMENT_SHADER_ARB
|
||||
// or STBGL_VERTEX_SHADER or STBGL_FRAGMENT_SHADER
|
||||
// sources array of strings containing the shader source
|
||||
// num_sources number of string in sources, or -1 meaning sources is NULL-terminated
|
||||
// error string to output compiler error to
|
||||
// error_buflen length of error buffer in chars
|
||||
|
||||
extern GLuint stbgl_link_program(GLuint vertex_shader, GLuint fragment_shader, char const **binds, int num_binds, char *error, int error_buflen);
|
||||
// links a shader. returns the linked program on success or 0 on failure.
|
||||
//
|
||||
// vertex_shader a compiled vertex shader from stbgl_compile_shader, or 0 for fixed-function (if legal)
|
||||
// fragment_shader a compiled fragment shader from stbgl_compile_shader, or 0 for fixed-function (if legal)
|
||||
//
|
||||
|
||||
extern void stbgl_delete_shader(GLuint shader);
|
||||
// deletes a shader created by stbgl_compile_shader
|
||||
|
||||
|
||||
///////////// RENDERING WITH SHADERS
|
||||
|
||||
extern GLint stbgl_find_uniform(GLuint prog, char *uniform);
|
||||
|
||||
extern void stbgl_find_uniforms(GLuint prog, GLint *locations, char const **uniforms, int num_uniforms);
|
||||
// Given the locations array that is num_uniforms long, fills out
|
||||
// the locations of each of those uniforms for the specified program.
|
||||
// If num_uniforms is -1, then uniforms[] must be NULL-terminated
|
||||
|
||||
// the following functions just wrap the difference in naming between GL2+ and ARB,
|
||||
// so you don't need them unless you're using both ARB and GL2+ in the same codebase,
|
||||
// or you're relying on this lib to provide the extensions
|
||||
extern void stbglUseProgram(GLuint program);
|
||||
extern void stbglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer);
|
||||
extern void stbglEnableVertexAttribArray(GLuint index);
|
||||
extern void stbglDisableVertexAttribArray(GLuint index);
|
||||
extern void stbglUniform1fv(GLint loc, GLsizei count, const GLfloat *v);
|
||||
extern void stbglUniform2fv(GLint loc, GLsizei count, const GLfloat *v);
|
||||
extern void stbglUniform3fv(GLint loc, GLsizei count, const GLfloat *v);
|
||||
extern void stbglUniform4fv(GLint loc, GLsizei count, const GLfloat *v);
|
||||
extern void stbglUniform1iv(GLint loc, GLsizei count, const GLint *v);
|
||||
extern void stbglUniform2iv(GLint loc, GLsizei count, const GLint *v);
|
||||
extern void stbglUniform3iv(GLint loc, GLsizei count, const GLint *v);
|
||||
extern void stbglUniform4iv(GLint loc, GLsizei count, const GLint *v);
|
||||
extern void stbglUniform1f(GLint loc, float v0);
|
||||
extern void stbglUniform2f(GLint loc, float v0, float v1);
|
||||
extern void stbglUniform3f(GLint loc, float v0, float v1, float v2);
|
||||
extern void stbglUniform4f(GLint loc, float v0, float v1, float v2, float v3);
|
||||
extern void stbglUniform1i(GLint loc, GLint v0);
|
||||
extern void stbglUniform2i(GLint loc, GLint v0, GLint v1);
|
||||
extern void stbglUniform3i(GLint loc, GLint v0, GLint v1, GLint v2);
|
||||
extern void stbglUniform4i(GLint loc, GLint v0, GLint v1, GLint v2, GLint v3);
|
||||
|
||||
|
||||
////////////// END OF FUNCTIONS
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // STB_GLPROG_STATIC
|
||||
|
||||
#ifdef STB_GLPROG_ARB
|
||||
#define STBGL_VERTEX_SHADER GL_VERTEX_SHADER_ARB
|
||||
#define STBGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER_ARB
|
||||
#else
|
||||
#define STBGL_VERTEX_SHADER GL_VERTEX_SHADER
|
||||
#define STBGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER
|
||||
#endif
|
||||
|
||||
#endif // INCLUDE_STB_GLPROG_H
|
||||
|
||||
|
||||
///////// header file section ends here
|
||||
|
||||
|
||||
#ifdef STB_GLPROG_IMPLEMENTATION
|
||||
#include <string.h> // strncpy
|
||||
|
||||
#ifdef STB_GLPROG_STATIC
|
||||
#define STB_GLPROG_DECLARE static
|
||||
#else
|
||||
#define STB_GLPROG_DECLARE extern
|
||||
#endif
|
||||
|
||||
// check if user wants this file to define the GL extensions itself
|
||||
#ifdef STB_GLPROG_ARB_DEFINE_EXTENSIONS
|
||||
#define STB_GLPROG_ARB // make sure later code uses the extensions
|
||||
|
||||
#ifndef STB_GLPROG_SUPPRESS_GLEXT_INCLUDE
|
||||
#include "glext.h"
|
||||
#endif
|
||||
|
||||
#define STB_GLPROG_EXTENSIONS \
|
||||
STB_GLPROG_FUNC(ATTACHOBJECT , AttachObject ) \
|
||||
STB_GLPROG_FUNC(BINDATTRIBLOCATION , BindAttribLocation ) \
|
||||
STB_GLPROG_FUNC(COMPILESHADER , CompileShader ) \
|
||||
STB_GLPROG_FUNC(CREATEPROGRAMOBJECT , CreateProgramObject ) \
|
||||
STB_GLPROG_FUNC(CREATESHADEROBJECT , CreateShaderObject ) \
|
||||
STB_GLPROG_FUNC(DELETEOBJECT , DeleteObject ) \
|
||||
STB_GLPROG_FUNC(DETACHOBJECT , DetachObject ) \
|
||||
STB_GLPROG_FUNC(DISABLEVERTEXATTRIBARRAY, DisableVertexAttribArray) \
|
||||
STB_GLPROG_FUNC(ENABLEVERTEXATTRIBARRAY, EnableVertexAttribArray ) \
|
||||
STB_GLPROG_FUNC(GETATTACHEDOBJECTS , GetAttachedObjects ) \
|
||||
STB_GLPROG_FUNC(GETOBJECTPARAMETERIV, GetObjectParameteriv) \
|
||||
STB_GLPROG_FUNC(GETINFOLOG , GetInfoLog ) \
|
||||
STB_GLPROG_FUNC(GETUNIFORMLOCATION , GetUniformLocation ) \
|
||||
STB_GLPROG_FUNC(LINKPROGRAM , LinkProgram ) \
|
||||
STB_GLPROG_FUNC(SHADERSOURCE , ShaderSource ) \
|
||||
STB_GLPROG_FUNC(UNIFORM1F , Uniform1f ) \
|
||||
STB_GLPROG_FUNC(UNIFORM2F , Uniform2f ) \
|
||||
STB_GLPROG_FUNC(UNIFORM3F , Uniform3f ) \
|
||||
STB_GLPROG_FUNC(UNIFORM4F , Uniform4f ) \
|
||||
STB_GLPROG_FUNC(UNIFORM1I , Uniform1i ) \
|
||||
STB_GLPROG_FUNC(UNIFORM2I , Uniform2i ) \
|
||||
STB_GLPROG_FUNC(UNIFORM3I , Uniform3i ) \
|
||||
STB_GLPROG_FUNC(UNIFORM4I , Uniform4i ) \
|
||||
STB_GLPROG_FUNC(UNIFORM1FV , Uniform1fv ) \
|
||||
STB_GLPROG_FUNC(UNIFORM2FV , Uniform2fv ) \
|
||||
STB_GLPROG_FUNC(UNIFORM3FV , Uniform3fv ) \
|
||||
STB_GLPROG_FUNC(UNIFORM4FV , Uniform4fv ) \
|
||||
STB_GLPROG_FUNC(UNIFORM1IV , Uniform1iv ) \
|
||||
STB_GLPROG_FUNC(UNIFORM2IV , Uniform2iv ) \
|
||||
STB_GLPROG_FUNC(UNIFORM3IV , Uniform3iv ) \
|
||||
STB_GLPROG_FUNC(UNIFORM4IV , Uniform4iv ) \
|
||||
STB_GLPROG_FUNC(USEPROGRAMOBJECT , UseProgramObject ) \
|
||||
STB_GLPROG_FUNC(VERTEXATTRIBPOINTER , VertexAttribPointer )
|
||||
|
||||
// define the static function pointers
|
||||
|
||||
#define STB_GLPROG_FUNC(x,y) static PFNGL##x##ARBPROC gl##y##ARB;
|
||||
STB_GLPROG_EXTENSIONS
|
||||
#undef STB_GLPROG_FUNC
|
||||
|
||||
// define the GetProcAddress
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WINGDIAPI
|
||||
#ifndef STB__HAS_WGLPROC
|
||||
typedef int (__stdcall *stbgl__voidfunc)(void);
|
||||
static __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *);
|
||||
#endif
|
||||
#endif
|
||||
#define STBGL__GET_FUNC(x) wglGetProcAddress(x)
|
||||
#else
|
||||
#error "need to define how this platform gets extensions"
|
||||
#endif
|
||||
|
||||
// create a function that fills out the function pointers
|
||||
|
||||
static void stb_glprog_init(void)
|
||||
{
|
||||
static int initialized = 0; // not thread safe!
|
||||
if (initialized) return;
|
||||
#define STB_GLPROG_FUNC(x,y) gl##y##ARB = (PFNGL##x##ARBPROC) STBGL__GET_FUNC("gl" #y "ARB");
|
||||
STB_GLPROG_EXTENSIONS
|
||||
#undef STB_GLPROG_FUNC
|
||||
}
|
||||
#undef STB_GLPROG_EXTENSIONS
|
||||
|
||||
#else
|
||||
static void stb_glprog_init(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// define generic names for many of the gl functions or extensions for later use;
|
||||
// note that in some cases there are two functions in core and one function in ARB
|
||||
#ifdef STB_GLPROG_ARB
|
||||
#define stbglCreateShader glCreateShaderObjectARB
|
||||
#define stbglDeleteShader glDeleteObjectARB
|
||||
#define stbglAttachShader glAttachObjectARB
|
||||
#define stbglDetachShader glDetachObjectARB
|
||||
#define stbglShaderSource glShaderSourceARB
|
||||
#define stbglCompileShader glCompileShaderARB
|
||||
#define stbglGetShaderStatus(a,b) glGetObjectParameterivARB(a, GL_OBJECT_COMPILE_STATUS_ARB, b)
|
||||
#define stbglGetShaderInfoLog glGetInfoLogARB
|
||||
#define stbglCreateProgram glCreateProgramObjectARB
|
||||
#define stbglDeleteProgram glDeleteObjectARB
|
||||
#define stbglLinkProgram glLinkProgramARB
|
||||
#define stbglGetProgramStatus(a,b) glGetObjectParameterivARB(a, GL_OBJECT_LINK_STATUS_ARB, b)
|
||||
#define stbglGetProgramInfoLog glGetInfoLogARB
|
||||
#define stbglGetAttachedShaders glGetAttachedObjectsARB
|
||||
#define stbglBindAttribLocation glBindAttribLocationARB
|
||||
#define stbglGetUniformLocation glGetUniformLocationARB
|
||||
#define stbgl_UseProgram glUseProgramObjectARB
|
||||
#else
|
||||
#define stbglCreateShader glCreateShader
|
||||
#define stbglDeleteShader glDeleteShader
|
||||
#define stbglAttachShader glAttachShader
|
||||
#define stbglDetachShader glDetachShader
|
||||
#define stbglShaderSource glShaderSource
|
||||
#define stbglCompileShader glCompileShader
|
||||
#define stbglGetShaderStatus(a,b) glGetShaderiv(a, GL_COMPILE_STATUS, b)
|
||||
#define stbglGetShaderInfoLog glGetShaderInfoLog
|
||||
#define stbglCreateProgram glCreateProgram
|
||||
#define stbglDeleteProgram glDeleteProgram
|
||||
#define stbglLinkProgram glLinkProgram
|
||||
#define stbglGetProgramStatus(a,b) glGetProgramiv(a, GL_LINK_STATUS, b)
|
||||
#define stbglGetProgramInfoLog glGetProgramInfoLog
|
||||
#define stbglGetAttachedShaders glGetAttachedShaders
|
||||
#define stbglBindAttribLocation glBindAttribLocation
|
||||
#define stbglGetUniformLocation glGetUniformLocation
|
||||
#define stbgl_UseProgram glUseProgram
|
||||
#endif
|
||||
|
||||
|
||||
// perform a safe strcat of 3 strings, given that we can't rely on portable snprintf
|
||||
// if you need to break on error, this is the best place to place a breakpoint
|
||||
static void stb_glprog_error(char *error, int error_buflen, char *str1, char *str2, char *str3)
|
||||
{
|
||||
int n = strlen(str1);
|
||||
strncpy(error, str1, error_buflen);
|
||||
if (n < error_buflen && str2) {
|
||||
strncpy(error+n, str2, error_buflen - n);
|
||||
n += strlen(str2);
|
||||
if (n < error_buflen && str3) {
|
||||
strncpy(error+n, str3, error_buflen - n);
|
||||
}
|
||||
}
|
||||
error[error_buflen-1] = 0;
|
||||
}
|
||||
|
||||
STB_GLPROG_DECLARE GLuint stbgl_compile_shader(GLenum type, char const **sources, int num_sources, char *error, int error_buflen)
|
||||
{
|
||||
char *typename = (type == STBGL_VERTEX_SHADER ? "vertex" : "fragment");
|
||||
int len;
|
||||
GLint result;
|
||||
GLuint shader;
|
||||
|
||||
// initialize the extensions if we haven't already
|
||||
stb_glprog_init();
|
||||
|
||||
// allocate
|
||||
|
||||
shader = stbglCreateShader(type);
|
||||
if (!shader) {
|
||||
stb_glprog_error(error, error_buflen, "Couldn't allocate shader object in stbgl_compile_shader for ", typename, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// compile
|
||||
|
||||
// if num_sources is negative, assume source is NULL-terminated and count the non-NULL ones
|
||||
if (num_sources < 0)
|
||||
for (num_sources = 0; sources[num_sources] != NULL; ++num_sources)
|
||||
;
|
||||
stbglShaderSource(shader, num_sources, sources, NULL);
|
||||
stbglCompileShader(shader);
|
||||
stbglGetShaderStatus(shader, &result);
|
||||
if (result)
|
||||
return shader;
|
||||
|
||||
// errors
|
||||
|
||||
stb_glprog_error(error, error_buflen, "Compile error for ", typename, " shader: ");
|
||||
len = strlen(error);
|
||||
if (len < error_buflen)
|
||||
stbglGetShaderInfoLog(shader, error_buflen-len, NULL, error+len);
|
||||
|
||||
stbglDeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
STB_GLPROG_DECLARE GLuint stbgl_link_program(GLuint vertex_shader, GLuint fragment_shader, char const **binds, int num_binds, char *error, int error_buflen)
|
||||
{
|
||||
int len;
|
||||
GLint result;
|
||||
|
||||
// allocate
|
||||
|
||||
GLuint prog = stbglCreateProgram();
|
||||
if (!prog) {
|
||||
stb_glprog_error(error, error_buflen, "Couldn't allocate program object in stbgl_link_program", NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// attach
|
||||
|
||||
if (vertex_shader)
|
||||
stbglAttachShader(prog, vertex_shader);
|
||||
if (fragment_shader)
|
||||
stbglAttachShader(prog, fragment_shader);
|
||||
|
||||
// attribute binds
|
||||
|
||||
if (binds) {
|
||||
int i;
|
||||
// if num_binds is negative, then it is NULL terminated
|
||||
if (num_binds < 0)
|
||||
for (num_binds=0; binds[num_binds]; ++num_binds)
|
||||
;
|
||||
for (i=0; i < num_binds; ++i)
|
||||
if (binds[i] && binds[i][0]) // empty binds can be NULL or ""
|
||||
stbglBindAttribLocation(prog, i, binds[i]);
|
||||
}
|
||||
|
||||
// link
|
||||
|
||||
stbglLinkProgram(prog);
|
||||
|
||||
// detach
|
||||
|
||||
if (vertex_shader)
|
||||
stbglDetachShader(prog, vertex_shader);
|
||||
if (fragment_shader)
|
||||
stbglDetachShader(prog, fragment_shader);
|
||||
|
||||
// errors
|
||||
|
||||
stbglGetProgramStatus(prog, &result);
|
||||
if (result)
|
||||
return prog;
|
||||
|
||||
stb_glprog_error(error, error_buflen, "Link error: ", NULL, NULL);
|
||||
len = strlen(error);
|
||||
if (len < error_buflen)
|
||||
stbglGetProgramInfoLog(prog, error_buflen-len, NULL, error+len);
|
||||
|
||||
stbglDeleteProgram(prog);
|
||||
return 0;
|
||||
}
|
||||
|
||||
STB_GLPROG_DECLARE GLuint stbgl_create_program(char const **vertex_source, char const **frag_source, char const **binds, char *error, int error_buflen)
|
||||
{
|
||||
GLuint vertex, fragment, prog=0;
|
||||
vertex = stbgl_compile_shader(STBGL_VERTEX_SHADER, vertex_source, -1, error, error_buflen);
|
||||
if (vertex) {
|
||||
fragment = stbgl_compile_shader(STBGL_FRAGMENT_SHADER, frag_source, -1, error, error_buflen);
|
||||
if (fragment)
|
||||
prog = stbgl_link_program(vertex, fragment, binds, -1, error, error_buflen);
|
||||
if (fragment)
|
||||
stbglDeleteShader(fragment);
|
||||
stbglDeleteShader(vertex);
|
||||
}
|
||||
return prog;
|
||||
}
|
||||
|
||||
STB_GLPROG_DECLARE void stbgl_delete_shader(GLuint shader)
|
||||
{
|
||||
stbglDeleteShader(shader);
|
||||
}
|
||||
|
||||
STB_GLPROG_DECLARE void stgbl_delete_program(GLuint program)
|
||||
{
|
||||
stbglDeleteProgram(program);
|
||||
}
|
||||
|
||||
GLint stbgl_find_uniform(GLuint prog, char *uniform)
|
||||
{
|
||||
return stbglGetUniformLocation(prog, uniform);
|
||||
}
|
||||
|
||||
STB_GLPROG_DECLARE void stbgl_find_uniforms(GLuint prog, GLint *locations, char const **uniforms, int num_uniforms)
|
||||
{
|
||||
int i;
|
||||
if (num_uniforms < 0)
|
||||
num_uniforms = 999999;
|
||||
for (i=0; i < num_uniforms && uniforms[i]; ++i)
|
||||
locations[i] = stbglGetUniformLocation(prog, uniforms[i]);
|
||||
}
|
||||
|
||||
STB_GLPROG_DECLARE void stbglUseProgram(GLuint program)
|
||||
{
|
||||
stbgl_UseProgram(program);
|
||||
}
|
||||
|
||||
#ifdef STB_GLPROG_ARB
|
||||
#define STBGL_ARBIFY(name) name##ARB
|
||||
#else
|
||||
#define STBGL_ARBIFY(name) name
|
||||
#endif
|
||||
|
||||
STB_GLPROG_DECLARE void stbglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer)
|
||||
{
|
||||
STBGL_ARBIFY(glVertexAttribPointer)(index, size, type, normalized, stride, pointer);
|
||||
}
|
||||
|
||||
STB_GLPROG_DECLARE void stbglEnableVertexAttribArray (GLuint index) { STBGL_ARBIFY(glEnableVertexAttribArray )(index); }
|
||||
STB_GLPROG_DECLARE void stbglDisableVertexAttribArray(GLuint index) { STBGL_ARBIFY(glDisableVertexAttribArray)(index); }
|
||||
|
||||
STB_GLPROG_DECLARE void stbglUniform1fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform1fv)(loc,count,v); }
|
||||
STB_GLPROG_DECLARE void stbglUniform2fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform2fv)(loc,count,v); }
|
||||
STB_GLPROG_DECLARE void stbglUniform3fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform3fv)(loc,count,v); }
|
||||
STB_GLPROG_DECLARE void stbglUniform4fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform4fv)(loc,count,v); }
|
||||
|
||||
STB_GLPROG_DECLARE void stbglUniform1iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform1iv)(loc,count,v); }
|
||||
STB_GLPROG_DECLARE void stbglUniform2iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform2iv)(loc,count,v); }
|
||||
STB_GLPROG_DECLARE void stbglUniform3iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform3iv)(loc,count,v); }
|
||||
STB_GLPROG_DECLARE void stbglUniform4iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform4iv)(loc,count,v); }
|
||||
|
||||
STB_GLPROG_DECLARE void stbglUniform1f(GLint loc, float v0)
|
||||
{ STBGL_ARBIFY(glUniform1f)(loc,v0); }
|
||||
STB_GLPROG_DECLARE void stbglUniform2f(GLint loc, float v0, float v1)
|
||||
{ STBGL_ARBIFY(glUniform2f)(loc,v0,v1); }
|
||||
STB_GLPROG_DECLARE void stbglUniform3f(GLint loc, float v0, float v1, float v2)
|
||||
{ STBGL_ARBIFY(glUniform3f)(loc,v0,v1,v2); }
|
||||
STB_GLPROG_DECLARE void stbglUniform4f(GLint loc, float v0, float v1, float v2, float v3)
|
||||
{ STBGL_ARBIFY(glUniform4f)(loc,v0,v1,v2,v3); }
|
||||
|
||||
STB_GLPROG_DECLARE void stbglUniform1i(GLint loc, GLint v0)
|
||||
{ STBGL_ARBIFY(glUniform1i)(loc,v0); }
|
||||
STB_GLPROG_DECLARE void stbglUniform2i(GLint loc, GLint v0, GLint v1)
|
||||
{ STBGL_ARBIFY(glUniform2i)(loc,v0,v1); }
|
||||
STB_GLPROG_DECLARE void stbglUniform3i(GLint loc, GLint v0, GLint v1, GLint v2)
|
||||
{ STBGL_ARBIFY(glUniform3i)(loc,v0,v1,v2); }
|
||||
STB_GLPROG_DECLARE void stbglUniform4i(GLint loc, GLint v0, GLint v1, GLint v2, GLint v3)
|
||||
{ STBGL_ARBIFY(glUniform4i)(loc,v0,v1,v2,v3); }
|
||||
|
||||
#endif
|
224
tests/caveview/win32/SDL_windows_main.c
Normal file
224
tests/caveview/win32/SDL_windows_main.c
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
SDL_windows_main.c, placed in the public domain by Sam Lantinga 4/13/98
|
||||
|
||||
The WinMain function -- calls your program's main() function
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
//#include "../../core/windows/SDL_windows.h"
|
||||
|
||||
/* Include this so we define UNICODE properly */
|
||||
#if defined(__WIN32__)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define STRICT
|
||||
#ifndef UNICODE
|
||||
#define UNICODE 1
|
||||
#endif
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/* Routines to convert from UTF8 to native Windows text */
|
||||
#if UNICODE
|
||||
#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(S), (SDL_wcslen(S)+1)*sizeof(WCHAR))
|
||||
#define WIN_UTF8ToString(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (char *)(S), SDL_strlen(S)+1)
|
||||
#else
|
||||
/* !!! FIXME: UTF8ToString() can just be a SDL_strdup() here. */
|
||||
#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "ASCII", (char *)(S), (SDL_strlen(S)+1))
|
||||
#define WIN_UTF8ToString(S) SDL_iconv_string("ASCII", "UTF-8", (char *)(S), SDL_strlen(S)+1)
|
||||
#endif
|
||||
|
||||
/* Sets an error message based on a given HRESULT */
|
||||
extern int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr);
|
||||
|
||||
/* Sets an error message based on GetLastError(). Always return -1. */
|
||||
extern int WIN_SetError(const char *prefix);
|
||||
|
||||
/* Wrap up the oddities of CoInitialize() into a common function. */
|
||||
extern HRESULT WIN_CoInitialize(void);
|
||||
extern void WIN_CoUninitialize(void);
|
||||
|
||||
/* Returns SDL_TRUE if we're running on Windows Vista and newer */
|
||||
extern BOOL WIN_IsWindowsVistaOrGreater();
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Include the SDL main definition header */
|
||||
#include "SDL.h"
|
||||
#include "SDL_main.h"
|
||||
|
||||
#ifdef main
|
||||
# undef main
|
||||
#endif /* main */
|
||||
|
||||
static void
|
||||
UnEscapeQuotes(char *arg)
|
||||
{
|
||||
char *last = NULL;
|
||||
|
||||
while (*arg) {
|
||||
if (*arg == '"' && (last != NULL && *last == '\\')) {
|
||||
char *c_curr = arg;
|
||||
char *c_last = last;
|
||||
|
||||
while (*c_curr) {
|
||||
*c_last = *c_curr;
|
||||
c_last = c_curr;
|
||||
c_curr++;
|
||||
}
|
||||
*c_last = '\0';
|
||||
}
|
||||
last = arg;
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a command line buffer into arguments */
|
||||
static int
|
||||
ParseCommandLine(char *cmdline, char **argv)
|
||||
{
|
||||
char *bufp;
|
||||
char *lastp = NULL;
|
||||
int argc, last_argc;
|
||||
|
||||
argc = last_argc = 0;
|
||||
for (bufp = cmdline; *bufp;) {
|
||||
/* Skip leading whitespace */
|
||||
while (SDL_isspace(*bufp)) {
|
||||
++bufp;
|
||||
}
|
||||
/* Skip over argument */
|
||||
if (*bufp == '"') {
|
||||
++bufp;
|
||||
if (*bufp) {
|
||||
if (argv) {
|
||||
argv[argc] = bufp;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
/* Skip over word */
|
||||
lastp = bufp;
|
||||
while (*bufp && (*bufp != '"' || *lastp == '\\')) {
|
||||
lastp = bufp;
|
||||
++bufp;
|
||||
}
|
||||
} else {
|
||||
if (*bufp) {
|
||||
if (argv) {
|
||||
argv[argc] = bufp;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
/* Skip over word */
|
||||
while (*bufp && !SDL_isspace(*bufp)) {
|
||||
++bufp;
|
||||
}
|
||||
}
|
||||
if (*bufp) {
|
||||
if (argv) {
|
||||
*bufp = '\0';
|
||||
}
|
||||
++bufp;
|
||||
}
|
||||
|
||||
/* Strip out \ from \" sequences */
|
||||
if (argv && last_argc != argc) {
|
||||
UnEscapeQuotes(argv[last_argc]);
|
||||
}
|
||||
last_argc = argc;
|
||||
}
|
||||
if (argv) {
|
||||
argv[argc] = NULL;
|
||||
}
|
||||
return (argc);
|
||||
}
|
||||
|
||||
/* Show an error message */
|
||||
static void
|
||||
ShowError(const char *title, const char *message)
|
||||
{
|
||||
/* If USE_MESSAGEBOX is defined, you need to link with user32.lib */
|
||||
#ifdef USE_MESSAGEBOX
|
||||
MessageBox(NULL, message, title, MB_ICONEXCLAMATION | MB_OK);
|
||||
#else
|
||||
fprintf(stderr, "%s: %s\n", title, message);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pop up an out of memory message, returns to Windows */
|
||||
static BOOL
|
||||
OutOfMemory(void)
|
||||
{
|
||||
ShowError("Fatal Error", "Out of memory - aborting");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/* The VC++ compiler needs main defined */
|
||||
#define console_main main
|
||||
#endif
|
||||
|
||||
/* This is where execution begins [console apps] */
|
||||
int
|
||||
console_main(int argc, char *argv[])
|
||||
{
|
||||
int status;
|
||||
|
||||
SDL_SetMainReady();
|
||||
|
||||
/* Run the application main() code */
|
||||
status = SDL_main(argc, argv);
|
||||
|
||||
/* Exit cleanly, calling atexit() functions */
|
||||
exit(status);
|
||||
|
||||
/* Hush little compiler, don't you cry... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is where execution begins [windowed apps] */
|
||||
int WINAPI
|
||||
WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
|
||||
{
|
||||
char **argv;
|
||||
int argc;
|
||||
char *cmdline;
|
||||
|
||||
/* Grab the command line */
|
||||
TCHAR *text = GetCommandLine();
|
||||
#if UNICODE
|
||||
cmdline = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char *)(text), (SDL_wcslen(text)+1)*sizeof(WCHAR));
|
||||
#else
|
||||
cmdline = SDL_strdup(text);
|
||||
#endif
|
||||
if (cmdline == NULL) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
|
||||
/* Parse it into argv and argc */
|
||||
argc = ParseCommandLine(cmdline, NULL);
|
||||
argv = SDL_stack_alloc(char *, argc + 1);
|
||||
if (argv == NULL) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
ParseCommandLine(cmdline, argv);
|
||||
|
||||
/* Run the main program */
|
||||
console_main(argc, argv);
|
||||
|
||||
SDL_stack_free(argv);
|
||||
|
||||
SDL_free(cmdline);
|
||||
|
||||
/* Hush little compiler, don't you cry... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __WIN32__ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
Loading…
Reference in New Issue
Block a user