Skip to content

Instantly share code, notes, and snippets.

@kraln
Created January 3, 2020 17:41
Show Gist options
  • Save kraln/97ee0c84d5e28229a13041b2e509c758 to your computer and use it in GitHub Desktop.
Save kraln/97ee0c84d5e28229a13041b2e509c758 to your computer and use it in GitHub Desktop.
Voxel Flying SDL Thing
// based very loosely on https://github.com/s-macke/VoxelSpace
#include <SDL.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <SDL_image.h>
static uint16_t S_WIDTH = 800;
static uint16_t S_HEIGHT = 600;
static const uint16_t D_WIDTH = 256;
static const uint16_t D_HEIGHT = 256;
static const uint16_t TEX_DIM = 150;
typedef struct RGB_S
{
uint8_t r;
uint8_t g;
uint8_t b;
uint32_t s;
} RGB_S_t;
void wrap(int32_t* val, int32_t min, int32_t max)
{
while (*val > max)
*val -= max;
while (*val < min)
*val += max;
}
void clamp(int32_t* val, int32_t min, int32_t max)
{
if (*val < min)
{
*val = min;
return;
}
if (*val > max)
{
*val = max;
return;
}
}
void set_pixel(SDL_Surface* dest, uint32_t x, uint32_t y, uint32_t col)
{
// ASSUME LOCKED SURFACE!
uint8_t bpp = dest->format->BytesPerPixel;
uint8_t* p = ((uint8_t*)dest->pixels) + (y * dest->pitch) + (x * bpp);
if (bpp == 1) *p = col;
if (bpp == 2) *(uint16_t*)p = col;
if (bpp == 3)
{
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
{
p[0] = col >> 16 & 0xFF;
p[1] = col >> 8 & 0xFF;
p[2] = col & 0xFF;
}
else
{
p[2] = col >> 16 & 0xFF;
p[1] = col >> 8 & 0xFF;
p[0] = col & 0xFF;
}
}
if (bpp == 4) *(uint32_t*)p = col;
}
void draw_line(SDL_Surface* destination, uint32_t x, uint32_t y_top, uint32_t y_bottom, RGB_S_t color)
{
/* ensure y_bottom < y_top */
if (y_bottom > y_top)
{
uint32_t temp = y_top;
y_top = y_bottom;
y_bottom = temp;
}
for (uint32_t y = y_bottom; y < y_top; y++)
{
set_pixel(destination, x, y, SDL_MapRGB(destination->format, color.r, color.g, color.b));
}
}
RGB_S_t get_pixel(SDL_Surface* source, uint32_t x, uint32_t y)
{
RGB_S_t ret = { 0 };
wrap(&x, 0, TEX_DIM);
wrap(&y, 0, TEX_DIM);
if (x > TEX_DIM || y > TEX_DIM)
{
printf("Invalid coordinates in get_pixel: %u,%u\n", x, y);
return ret;
}
uint8_t bpp = source->format->BytesPerPixel;
uint8_t* p = (uint8_t*)source->pixels + y * source->pitch + x * bpp;
if (bpp == 1) ret.s = *p;
if (bpp == 2) ret.s = *(uint16_t*)p;
if (bpp == 3)
{
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
{
ret.s = p[0] << 16 | p[1] << 8 | p[2];
}
else
{
ret.s = p[0] | p[1] << 8 | p[2] << 16;
}
}
if (bpp == 4) ret.s = *(uint32_t*)p;
SDL_GetRGB(ret.s, source->format, &ret.r, &ret.g, &ret.b);
return ret;
}
void test(SDL_Surface* dest, SDL_Surface* col)
{
SDL_LockSurface(dest);
SDL_LockSurface(col);
for (uint16_t z = 200; z > 0; z--)
{
RGB_S_t color = { 0 };
for (uint16_t x = 0; x < 256; x++)
{
color.r = rand() % 255;
color.g = x % 255;
color.b = z % 255;
draw_line(dest, x, 255 - z, 255, color);
}
}
SDL_UnlockSurface(dest);
SDL_UnlockSurface(col);
}
void render(int32_t x, int32_t y, uint16_t height, uint16_t horizon, float scale_height, uint16_t distance, SDL_Surface* height_map, SDL_Surface* color_map, SDL_Surface* destination)
{
SDL_LockSurface(destination);
SDL_LockSurface(color_map);
SDL_LockSurface(height_map);
// back to front
float z_step = 1.f;
for (float z = distance; z > 0; z -= z_step)
{
int32_t xl = -z + x;
int32_t yl = -z + y;
int32_t xr = z + x;
int32_t yr = -z + y;
wrap(&xl, 0, TEX_DIM);
wrap(&xr, 0, TEX_DIM);
float dx = (xr - xl) / (float)400;
for (uint32_t i = 0; i < D_WIDTH; i++)
{
uint32_t height_on_screen = ((height - get_pixel(height_map, xl, yl).r) / (float)(z * scale_height)) + horizon;
clamp(&height_on_screen, 0, D_HEIGHT);
draw_line(destination, i, height_on_screen, D_HEIGHT, get_pixel(color_map, xl, yl));
xl = (uint16_t)(dx * i);
}
}
SDL_UnlockSurface(destination);
SDL_UnlockSurface(color_map);
SDL_UnlockSurface(height_map);
}
int main(int a, char* b[])
{
SDL_Window* window = NULL;
SDL_Surface* screenSurface = NULL;
SDL_Surface* bufferSurface = NULL;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL Error initializing! Error %s\n", SDL_GetError());
return -1;
}
window = SDL_CreateWindow("SDL App", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, S_WIDTH, S_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if (window == NULL)
{
printf("SDL Error Window! Error %s\n", SDL_GetError());
return -2;
}
screenSurface = SDL_GetWindowSurface(window);
bool quit = false;
SDL_Event e;
srand((unsigned int)time(NULL));
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & IMG_INIT_PNG))
{
printf("Could not initialize SDL_Image!. Error: %s\n", IMG_GetError());
return -1;
}
printf("Loading Texture Data\n");
SDL_Surface* s_color;
SDL_Surface* s_height;
SDL_Surface* t = IMG_Load("../color.png");
if (t == NULL)
{
printf("Couldn't load Color image.");
return -1;
}
s_color = SDL_ConvertSurface(t, screenSurface->format, 0);
SDL_FreeSurface(t);
t = IMG_Load("../height.png");
if (t == NULL)
{
printf("Couldn't load Height image.");
return -1;
}
s_height = SDL_ConvertSurface(t, screenSurface->format, 0);
SDL_FreeSurface(t);
// create buffer
bufferSurface = SDL_CreateRGBSurfaceWithFormat(0, D_WIDTH, D_HEIGHT, 32, SDL_PIXELFORMAT_RGBA8888);
printf("Entering main loop!\n");
int32_t x, y;
x = 1; y = 0;
bool K_up = false;
bool K_down = false;
bool K_left = false;
bool K_right = false;
while (!quit)
{
while (SDL_PollEvent(&e) != 0)
{
switch (e.type)
{
case SDL_QUIT:
quit = true;
printf("Quit Requested.\n");
continue;
case SDL_WINDOWEVENT:
switch (e.window.event)
{
case SDL_WINDOWEVENT_RESIZED:
S_WIDTH = e.window.data1;
S_HEIGHT = e.window.data2;
screenSurface = SDL_GetWindowSurface(window);
printf("Window resized. New size: %dx%d\n", S_WIDTH, S_HEIGHT);
break;
}
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
{
bool hit = e.type == SDL_KEYDOWN;
switch (e.key.keysym.sym)
{
case SDLK_LEFT:
K_left = hit;
break;
case SDLK_RIGHT:
K_right = hit;
break;
case SDLK_UP:
K_up = hit;
break;
case SDLK_DOWN:
K_down = hit;
}
}
break;
default:
printf("SDL Event! %d\n", e.type);
}
}
if (K_down) y++;
if (K_up) y--;
if (K_left) x--;
if (K_right) x++;
SDL_FillRect(bufferSurface, NULL, SDL_MapRGBA(bufferSurface->format, 0, 0, 0x7F, 0xFF));
render(
0, // x
y, // y
95, // height
100, // horizon
1.1, // scale_height
20, // distance
s_height, s_color, bufferSurface
);
//test(bufferSurface, s_color);
SDL_BlitScaled(bufferSurface, 0, screenSurface, 0);
SDL_UpdateWindowSurface(window);
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment