Created
January 3, 2020 17:41
-
-
Save kraln/97ee0c84d5e28229a13041b2e509c758 to your computer and use it in GitHub Desktop.
Voxel Flying SDL Thing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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