Created
February 26, 2016 00:02
-
-
Save TerrorBite/423de4e81e6c4a785661 to your computer and use it in GitHub Desktop.
Framebuffer rendering 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
#!/bin/sh | |
gcc -std=gnu99 -o fbtoy main.c framebuffer.c draw.c -lm -g |
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
#include "draw.h" | |
framebuffer* draw_fb; | |
ARGB_color active_color; | |
const int CLIP_INSIDE = 0; | |
const int CLIP_LEFT = 1; | |
const int CLIP_RIGHT = 2; | |
const int CLIP_BOTTOM = 4; | |
const int CLIP_TOP = 8; | |
void draw_setfb(framebuffer* fb) { | |
draw_fb = fb; | |
} | |
framebuffer* draw_getfb(framebuffer* fb) { | |
return draw_fb; | |
} | |
void draw_setcolor(ARGB_color color) { | |
active_color = color; | |
} | |
typedef void (*_linedraw_func)(double, double, double, double); | |
int _clip_get_outcode(double x, double y) { | |
int code = CLIP_INSIDE; | |
int xmax = draw_fb->vinfo.xres-1, ymax = draw_fb->vinfo.yres-1; | |
if(x<0) code |= CLIP_LEFT; | |
else if(x>xmax) code |= CLIP_RIGHT; | |
if(y<0) code |= CLIP_BOTTOM; | |
else if(y>ymax) code |= CLIP_TOP; | |
return code; | |
} | |
void _clip(_linedraw_func func, double x0, double y0, double x1, double y1) { | |
const int xmin = 0, ymin = 0; | |
int xmax = draw_fb->vinfo.xres-1, ymax = draw_fb->vinfo.yres-1; | |
int outcode0 = _clip_get_outcode(x0, y0); | |
int outcode1 = _clip_get_outcode(x1, y1); | |
int accept = 0; | |
while(1) { | |
if(!(outcode0 | outcode1)) { | |
/* Line is entirely within the viewport */ | |
accept = 1; | |
break; | |
} else if(outcode0 & outcode1) { | |
/* A line drawn between these points will not cross the viewport at all */ | |
break; | |
} else { | |
/* A line drawn between these points will cross the edge of the viewport */ | |
/* So we need to clip it */ | |
double x, y; | |
/* at least one outcode is outside the viewport, grab the first one */ | |
int outside = outcode0 ? outcode0 : outcode1; | |
int dx = (x1 - x0), dy = (y1 - y0); | |
/* Find the intersection point */ | |
if(outside & CLIP_TOP) { // point is above the viewport | |
x = x0 + dx * (ymax - y0) / dy; | |
y = ymax; | |
} else if(outside & CLIP_BOTTOM) { // point is below the viewport | |
x = x0 + dx * (ymin - y0) / dy; | |
y = ymin; | |
} else if(outside & CLIP_RIGHT) { // point is to the right | |
y = y0 + dy * (xmax - x0) / dx; | |
x = xmax; | |
} else if(outside & CLIP_LEFT) { // to the left | |
y = y0 + dy * (xmin - x0) / dx; | |
x = xmin; | |
} | |
/* Move outside point to intersection point */ | |
if(outside == outcode0) { | |
x0 = x; y0 = y; | |
outcode0 = _clip_get_outcode(x0, y0); | |
} else { | |
x1 = x; y1 = y; | |
outcode1 = _clip_get_outcode(x1, y1); | |
} | |
} | |
} | |
if(accept) (*func)(x0, y0, x1, y1); | |
} | |
void _draw_line(double x0, double y0, double x1, double y1) { | |
/* Implements Bresenham's line algorithm in software */ | |
int8_t xsign = (x1>x0)?1:-1, ysign = (y1>y0)?1:-1; | |
x0 = round(x0); x1=round(x1); | |
y0 = round(y0); y1=round(y1); | |
double dx = (x1-x0)*xsign, dy = (y1-y0)*ysign, error = 0.0, delta; | |
int i, x=x0, y=y0; | |
/* To improve accuracy, we swap x and y depending on slope */ | |
if(dx > dy) { | |
for(i=0; i<=dx; i++, x+=xsign) { | |
draw_point(x, y); | |
error += dy; | |
while(error >= dx) { | |
y += ysign; | |
error -= dx; | |
} | |
} | |
} else { | |
for(i=0; i<=dy; i++, y+=ysign) { | |
draw_point(x, y); | |
error += dx; | |
while(error >= dy) { | |
x += xsign; | |
error -= dy; | |
} | |
} | |
} | |
} | |
/*void draw_line_int(int x0, int y0, int x1, int y1) { | |
_clip(&_draw_line, (double)x0, (double)y0, (double)x1, (double)y1); | |
}*/ | |
void draw_line(double x0, double y0, double x1, double y1) { | |
_clip(&_draw_line, x0, y0, x1, y1); | |
} | |
inline double round(const double r) { return floor(r)+0.5; } | |
#define draw_point_asqrt(x,y,alpha) draw_point_alpha(x,y,sqrt(alpha)) | |
void _draw_line_aa(double x0, double y0, double x1, double y1) { | |
/* Implements Xiaolin Wu's line algorithm in software */ | |
/*uint8_t xsign = (x1>x0)?1:-1, ysign = (y1>y0)?1:-1;*/ | |
int steep = fabs(y1-y0) > fabs(x1-x0); | |
double temp; | |
if(steep) { | |
temp=x0; x0=y0; y0=temp; /* swap(x0, y0) */ | |
temp=x1; x1=y1; y1=temp; /* swap(x1, y1) */ | |
} | |
if(x0 > x1) { | |
temp=x0; x0=x1; x1=temp; /* swap(x0, x1) */ | |
temp=y0; y0=y1; y1=temp; /* swap(y0, y1) */ | |
} | |
double dx = x1 - x0, dy = y1 - y0; | |
double gradient = dy / dx; | |
double xend, yend, xgap, ygap; | |
/* Calculate first endpoint */ | |
xend = round(x0); | |
yend = y0 + gradient * (xend - x0); | |
xgap = 1.0-modf(x0+0.5, &temp); /* throw away integer part */ | |
ygap = modf(yend, &temp); | |
int intx1 = (int)xend, inty1 = (int)temp; /* will be used in the main loop */ | |
/* Draw first endpoint */ | |
if(steep) { | |
draw_point_asqrt(inty1, intx1, (1.0-ygap)*xgap); | |
draw_point_asqrt(inty1+1, intx1, ygap*xgap); | |
} else { | |
draw_point_asqrt(intx1, inty1, (1.0-ygap)*xgap); | |
draw_point_asqrt(intx1, inty1+1, ygap*xgap); | |
} | |
double y_inter = yend + gradient; /* First y-intersect for main loop */ | |
/* Calculate second endpoint */ | |
xend = round(x1); | |
yend = y1 + gradient * (xend - x1); | |
xgap = modf(x1+0.5, &temp); /* throw away integer part */ | |
ygap = modf(yend, &temp); | |
int intx2 = (int)xend, inty2 = (int)temp; | |
/* Draw second endpoint */ | |
if(steep) { | |
draw_point_asqrt(inty2, intx2, (1.0-ygap)*xgap); | |
draw_point_asqrt(inty2+1, intx2, ygap*xgap); | |
} else { | |
draw_point_asqrt(intx2, inty2, (1.0-ygap)*xgap); | |
draw_point_asqrt(intx2, inty2+1, ygap*xgap); | |
} | |
/* main loop */ | |
double f_yint; | |
int x, i_yint; | |
for(x = intx1+1; x<intx2; x++) { | |
f_yint = modf(y_inter, &temp); i_yint = (int)temp; | |
if(steep) { | |
draw_point_asqrt(i_yint, x, 1.0-f_yint); | |
draw_point_asqrt(i_yint+1, x, f_yint); | |
} else { | |
draw_point_asqrt(x, i_yint, 1.0-f_yint); | |
draw_point_asqrt(x, i_yint+1, f_yint); | |
} | |
y_inter += gradient; | |
} | |
} | |
void draw_line_aa(double x0, double y0, double x1, double y1) { | |
_clip(&_draw_line_aa, x0, y0, x1, y1); | |
} | |
void draw_point(int x, int y) { | |
if(_clip_get_outcode(x,y)) return; | |
fb_setpixel(draw_fb, x, y, active_color); | |
} | |
void draw_point_alpha(int x, int y, double alpha) { | |
/* Compositing */ | |
ARGB color; | |
color.argb = active_color; color.a = alpha*255; | |
fb_blend_over(draw_fb, x, y, color.argb); | |
} | |
void draw_clear(void) { | |
fb_clear(draw_fb); | |
} |
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
#ifndef _DRAW_H | |
#define _DRAW_H | |
#include <math.h> | |
#include "framebuffer.h" | |
#define ARGB_WHITE 0xFFFFFFFFu | |
#define ARGB_BLACK 0xFF000000u | |
#define ARGB_RED 0xFFFF0000u | |
#define ARGB_GREEN 0xFF00FF00u | |
#define ARGB_BLUE 0xFF0000FFu | |
#define ARGB_YELLOW 0xFFFFFF00u | |
#define ARGB_MAGENTA 0xFFFF00FFu | |
#define ARGB_CYAN 0xFF00FFFFu | |
#define ARGB_GREY 0xFF666666u | |
#define ARGB_LIGHTGREY 0xFFAAAAAAu | |
void draw_setfb(framebuffer* fb); | |
framebuffer* draw_getfb(); | |
void draw_setcolor(ARGB_color color); | |
/*void draw_line_int(int x1, int y1, int x2, int y2);*/ | |
void draw_line(double x0, double y0, double x1, double y1); | |
void draw_line_aa(double x0, double y0, double x1, double y1); | |
void draw_point(int x, int y); | |
void draw_point_alpha(int x, int y, double alpha); | |
void draw_clear(void); | |
#endif |
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
#include "framebuffer.h" | |
framebuffer* fb_open(int index, int flags) { | |
char filename[16]; | |
framebuffer* fb; | |
fb = malloc(sizeof(framebuffer)); | |
sprintf(filename, "/dev/fb%d", index); | |
/* Try to open the file */ | |
fb->fd = open(filename, O_RDWR); | |
if(fb->fd < 0) { | |
printf("Failed to open /dev/fb0 - aborting\n"); | |
return NULL; | |
} | |
/* Get information about framebuffer */ | |
if(ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vinfo) < 0) { | |
printf("ioctl failed!\n"); | |
return NULL; | |
} | |
fb->vinfo.bits_per_pixel = FBTEST_BPP; | |
fb->vinfo.yres_virtual = 2*fb->vinfo.yres_virtual; | |
printf("Doubling buffer to %d lines (if possible)... ", fb->vinfo.yres_virtual); | |
if(ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vinfo) < 0) { | |
printf("ioctl failed!\n"); | |
return NULL; | |
}; | |
fb->width = fb->vinfo.xres; | |
fb->height = fb->vinfo.yres; | |
printf("%d lines\n", fb->vinfo.yres_virtual); | |
ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->finfo); | |
/* Calculate framebuffer length in bytes */ | |
fb->size = fb->vinfo.yres_virtual * fb->finfo.line_length; | |
printf("Framebuffer length is 0x%zx (%zd) bytes\nPerforming mmap... ", fb->size, fb->size); | |
/* Map the framebuffer into memory*/ | |
fb->buffer = (uint32_t*)mmap(NULL, fb->size, PROT_READ|PROT_WRITE, MAP_SHARED, fb->fd, 0); | |
printf("mapped to %p\n", fb->buffer); | |
return fb; | |
} | |
int fb_close(framebuffer* fb) { | |
if(fb != NULL && fb->buffer != NULL) { | |
munmap(fb->buffer, fb->size); | |
fb->buffer = NULL; | |
close(fb->fd); | |
free(fb); | |
} | |
} | |
void fb_fill(framebuffer* fb, ARGB_color color) { | |
const int limit = fb->size>>2; | |
int i=0; | |
for(i=0; i < limit; i++) fb->buffer[i]=color; | |
} | |
int _getindex(framebuffer* fb, int x, int y) { | |
/* This assumes that the buffer is 32bpp */ | |
int index=(x+fb->vinfo.xoffset) + (y+fb->vinfo.yoffset) * fb->vinfo.xres_virtual; | |
#ifdef DEBUG_TRAP_OOB | |
if(index<0 || index >= fb->size>>2) { | |
printf("Aborting: Out of bounds write detected (x=%d, y=%d)\n", x, y); | |
fb_close(fb); | |
exit(-1); | |
} | |
#endif | |
return index; | |
} | |
void fb_setpixel(framebuffer* fb, int x, int y, ARGB_color value) { | |
fb->buffer[_getindex(fb,x,y)] = value; | |
} | |
void fb_blend_over(framebuffer* fb, int x, int y, ARGB_color value) { | |
int index = _getindex(fb, x, y); | |
ARGB bg, fg, color; | |
bg.argb = fb->buffer[index]; | |
fg.argb = value; | |
float alpha = (float)fg.a / 255; | |
color.r = fg.r*alpha + bg.r*(1-alpha); | |
color.g = fg.g*alpha + bg.g*(1-alpha); | |
color.b = fg.b*alpha + bg.b*(1-alpha); | |
color.a = 255; | |
fb->buffer[index] = color.argb; | |
} | |
ARGB_color fb_getpixel(framebuffer* fb, int x, int y) { | |
return fb->buffer[_getindex(fb,x,y)]; | |
} | |
void fb_clear(framebuffer* fb) { | |
memset(fb->buffer, 0, fb->size); | |
} | |
ARGB_color fb_rgb(framebuffer* fb, uint8_t r, uint8_t g, uint8_t b) { | |
return (r<<fb->vinfo.red.offset) | | |
(g<<fb->vinfo.green.offset) | | |
(b<<fb->vinfo.blue.offset); | |
} | |
ARGB_color fb_rgba(framebuffer* fb, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { | |
return fb_rgb(fb, r, g, b) | (a<<fb->vinfo.transp.offset); | |
} |
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
#ifndef _FRAMEBUFFER_H | |
#define _FRAMEBUFFER_H | |
#include <sys/mman.h> | |
#include <sys/types.h> | |
#include <sys/ioctl.h> | |
#include <linux/fb.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <string.h> | |
#define FBTEST_FLAGS_NONE 0 | |
#define FBTEST_BPP 32; | |
#define DEBUG_TRAP_OOB | |
typedef struct { | |
int fd; | |
uint16_t width, height; | |
uint32_t* buffer; | |
size_t size; | |
uint32_t flags; | |
struct fb_var_screeninfo vinfo; | |
struct fb_fix_screeninfo finfo; | |
} framebuffer; | |
typedef uint32_t ARGB_color; | |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | |
typedef union { | |
ARGB_color argb; | |
struct { | |
uint8_t b; | |
uint8_t g; | |
uint8_t r; | |
uint8_t a; | |
}; | |
} ARGB; | |
#else | |
typedef union { | |
ARGB_color argb; | |
struct { | |
uint8_t a; | |
uint8_t r; | |
uint8_t g; | |
uint8_t b; | |
}; | |
} ARGB; | |
#endif | |
framebuffer* fb_open(int index, int flags); | |
int fb_close(framebuffer* fb); | |
void fb_fill(framebuffer* fb, uint32_t color); | |
void fb_setpixel(framebuffer* fb, int x, int y, uint32_t value); | |
void fb_blend_over(framebuffer* fb, int x, int y, uint32_t value); | |
ARGB_color fb_getpixel(framebuffer* fb, int x, int y); | |
void fb_clear(framebuffer* fb); | |
ARGB_color fb_rgb(framebuffer* fb, uint8_t r, uint8_t g, uint8_t b); | |
ARGB_color fb_rgba(framebuffer* fb, uint8_t r, uint8_t g, uint8_t b, uint8_t a); | |
#endif |
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
#include "main.h" | |
int main(int argc, char* argv[], char* env[]) { | |
int i, j; | |
printf("Welcome to framebuffer test\n"); | |
framebuffer* fb = fb_open(0, FBTEST_FLAGS_NONE); | |
/* Do a test */ | |
printf("Bits Per Pixel: %d\n" | |
"Value | Off | Len | Shift\n" | |
" Red | %3d | %3d | %3d\n" | |
"Green | %3d | %3d | %3d\n" | |
" Blue | %3d | %3d | %3d\n" | |
"Alpha | %3d | %3d | %3d\n", | |
fb->vinfo.bits_per_pixel, | |
fb->vinfo.red.offset, fb->vinfo.red.length, fb->vinfo.red.msb_right, | |
fb->vinfo.green.offset, fb->vinfo.green.length, fb->vinfo.green.msb_right, | |
fb->vinfo.blue.offset, fb->vinfo.blue.length, fb->vinfo.blue.msb_right, | |
fb->vinfo.transp.offset, fb->vinfo.transp.length, fb->vinfo.transp.msb_right); | |
printf("Assuming 32bpp ARGB format\n"); | |
draw_setfb(fb); | |
/* Define a set of lines to draw * / | |
double lines[23][4] = { | |
{-5.0, -5.0, -5.0, 5.0}, | |
{-4.0, -5.0, -4.0, 5.0}, | |
{-3.0, -5.0, -3.0, 5.0}, | |
{-2.0, -5.0, -2.0, 5.0}, | |
{-1.0, -5.0, -1.0, 5.0}, | |
{0.0, -5.0, 0.0, 5.0}, | |
{1.0, -5.0, 1.0, 5.0}, | |
{2.0, -5.0, 2.0, 5.0}, | |
{3.0, -5.0, 3.0, 5.0}, | |
{4.0, -5.0, 4.0, 5.0}, | |
{5.0, -5.0, 5.0, 5.0}, | |
{-5.0, -5.0, 5.0, -5.0}, | |
{-5.0, -4.0, 5.0, -4.0}, | |
{-5.0, -3.0, 5.0, -3.0}, | |
{-5.0, -2.0, 5.0, -2.0}, | |
{-5.0, -1.0, 5.0, -1.0}, | |
{-5.0, 0.0, 5.0, 0.0}, | |
{-5.0, 1.0, 5.0, 1.0}, | |
{-5.0, 2.0, 5.0, 2.0}, | |
{-5.0, 3.0, 5.0, 3.0}, | |
{-5.0, 4.0, 5.0, 4.0}, | |
{-5.0, 5.0, 5.0, 5.0}, | |
{NAN, NAN, NAN, NAN} | |
}; | |
double camera_posx = 0.0, camera_posy = 0.0, camera_rotation = 0.0; | |
for(double* line=(double*)lines;;line+=4) { | |
if(isnan(line[0])) break; | |
/ *printf("%f, %f, %f, %f\n", line[0], line[1], line[2], line[3]);* / | |
3d_draw(line, camera_posx, camera_posy, 2.0, camera_rotation); | |
} | |
printf("End of list\n"); | |
*/ | |
camera3d cam = { | |
.xpos = 0.0, | |
.ypos = 2.0, | |
.zpos = -10.0, | |
.yaw = 0.0, | |
.pitch = 0.0, | |
.fov = 1.0, | |
.distort = 0.0 | |
}; /* camera position/rotation */ | |
test_render(cam); | |
/* Get a nice keyboard. Later we might use raw mode */ | |
static struct termios old_t, new_t; | |
tcgetattr(STDIN_FILENO, &old_t); | |
new_t = old_t; | |
new_t.c_lflag &= ~(ICANON|ECHO); /* disable ICANON and ECHO */ | |
/* cfmakeraw(new_t); */ | |
tcsetattr(STDIN_FILENO, TCSANOW, &new_t); | |
setvbuf(stdin, NULL, _IONBF, 0); | |
while(1) { | |
char input = getchar(); | |
switch(input) { | |
case '4': | |
cam.yaw -= 0.1/cam.fov; | |
break; | |
case '6': | |
cam.yaw += 0.1/cam.fov; | |
break; | |
case '2': | |
cam.pitch += 0.1/cam.fov; | |
if(cam.pitch > HALF_PI) cam.pitch = HALF_PI; | |
break; | |
case '8': | |
cam.pitch -= 0.1/cam.fov; | |
if(cam.pitch < -HALF_PI) cam.pitch = -HALF_PI; | |
break; | |
case '+': | |
cam.fov *= 1.25; | |
break; | |
case '-': | |
cam.fov *= 0.8; | |
break; | |
case '5': | |
cam.yaw = 0.0; | |
cam.pitch = 0.0; | |
cam.fov = 1.0; | |
cam.distort = 0.0; | |
break; | |
case 'w': | |
cam.zpos += 0.8; | |
break; | |
case 's': | |
cam.zpos -= 0.8; | |
break; | |
case 'a': | |
cam.xpos -= 0.8; | |
break; | |
case 'd': | |
cam.xpos += 0.8; | |
break; | |
case '*': | |
cam.distort += 0.1; | |
break; | |
case '/': | |
cam.distort -= 0.1; | |
break; | |
case 'q': | |
goto close; | |
} | |
test_render(cam); | |
} | |
close: | |
setvbuf(stdin, NULL, _IOFBF, 0); | |
tcsetattr(STDIN_FILENO, TCSANOW, &old_t); | |
fb_close(fb); | |
return 0; | |
} | |
void test_render(camera3d cam) { | |
draw_clear(); | |
/* Draw horizon line */ | |
draw_setcolor(ARGB_GREY); | |
double hpos = (0.5+tan(cam.pitch)*cam.fov)*480; | |
draw_line(0.0, hpos, 640.0, hpos); | |
/* Draw point grid */ | |
draw_setcolor(ARGB_WHITE); | |
for(double wx=-20.0; wx<20.01; wx++) { | |
for(double wz=-20.0; wz<20.01; wz++) { | |
point_3d(wx, 0.0, wz, cam); | |
} | |
} | |
/* Draw a cube */ | |
/* Define a set of lines to draw */ | |
double lines[13][6] = { | |
{5.5, 0.0, 5.5, 6.5, 0.0, 5.5}, | |
{5.5, 0.0, 5.5, 5.5, 0.0, 6.5}, | |
{6.5, 0.0, 5.5, 6.5, 0.0, 6.5}, | |
{5.5, 0.0, 6.5, 6.5, 0.0, 6.5}, | |
{5.5, 1.0, 5.5, 6.5, 1.0, 5.5}, | |
{5.5, 1.0, 5.5, 5.5, 1.0, 6.5}, | |
{6.5, 1.0, 5.5, 6.5, 1.0, 6.5}, | |
{5.5, 1.0, 6.5, 6.5, 1.0, 6.5}, | |
{5.5, 0.0, 5.5, 5.5, 1.0, 5.5}, | |
{5.5, 0.0, 6.5, 5.5, 1.0, 6.5}, | |
{6.5, 0.0, 5.5, 6.5, 1.0, 5.5}, | |
{6.5, 0.0, 6.5, 6.5, 1.0, 6.5}, | |
{NAN, NAN, NAN, NAN, NAN, NAN} | |
}; | |
for(double* line=(double*)lines;;line+=6) { | |
if(isnan(line[0])) break; | |
//printf("%f, %f, %f, %f, %f, %f\n", line[0], line[1], line[2], line[3], line[4], line[5]); | |
draw_3d(line, cam); | |
} | |
} | |
void point_3d(double wx, double wy, double wz, camera3d cam) { | |
/* Translation in 3D space*/ | |
wx -= cam.xpos; wy -= cam.ypos; wz -= cam.zpos; | |
/* Rotation in 3D space (around Y axis): Camera yaw */ | |
double rx = wx*cos(cam.yaw) - wz*sin(cam.yaw), | |
rz = wx*sin(cam.yaw) + wz*cos(cam.yaw); | |
/* Second rotation (around X axis): Camera pitch */ | |
wz = rz; | |
double ry = wy*cos(cam.pitch) - wz*sin(cam.pitch); | |
rz = wy*sin(cam.pitch) + wz*cos(cam.pitch); | |
/* Discard any points that are now "behind" us i.e. the Z value is negative */ | |
if(rz <= 0) { | |
//printf("Discarding point %f,%f,%f\n", rx,ry,rz); | |
return; | |
} | |
//printf("Drawing point %f,%f,%f\n", rx,ry,rz); | |
/* Map to screen coordinates */ | |
double sy = -ry / rz * cam.fov; | |
double sx = rx / rz * cam.fov; | |
screen_draw_point(sx, sy); | |
} | |
void draw_3d(double points[], camera3d cam) { | |
/* Translation in 3D space*/ | |
double wx0 = points[0] - cam.xpos, wx1 = points[3] - cam.xpos; | |
double wy0 = points[1] - cam.ypos, wy1 = points[4] - cam.ypos; | |
double wz0 = points[2] - cam.zpos, wz1 = points[5] - cam.zpos; | |
/* Rotation in 3D space (around Y axis): Camera yaw */ | |
double rx0 = wx0*cos(cam.yaw) - wz0*sin(cam.yaw), | |
rz0 = wx0*sin(cam.yaw) + wz0*cos(cam.yaw); | |
double rx1 = wx1*cos(cam.yaw) - wz1*sin(cam.yaw), | |
rz1 = wx1*sin(cam.yaw) + wz1*cos(cam.yaw); | |
/* Second rotation (around X axis): Camera pitch */ | |
wz0 = rz0; wz1 = rz1; | |
double ry0 = wy0*cos(cam.pitch) - wz0*sin(cam.pitch); | |
rz0 = wy0*sin(cam.pitch) + wz0*cos(cam.pitch); | |
double ry1 = wy1*cos(cam.pitch) - wz1*sin(cam.pitch); | |
rz1 = wy1*sin(cam.pitch) + wz1*cos(cam.pitch); | |
if(rz0 <= 0 || rz1 <= 0) { | |
// help I need a front clipping plane here | |
// Just bail out instead | |
return; | |
} | |
/* Translate 3d lines to 2d screen space */ | |
double sy0 = -ry0/rz0 * cam.fov, | |
sx0 = rx0/rz0 * cam.fov, | |
sy1 = -ry1/rz1 * cam.fov, | |
sx1 = rx1/rz1 * cam.fov; | |
/* map center-origin screen coords to pixels */ | |
double px0 = (0.5+sx0)*480, | |
px1 = (0.5+sx1)*480, | |
py0 = (0.5+sy0)*480, | |
py1 = (0.5+sy1)*480; | |
draw_line_aa(px0, py0, px1, py1); | |
} | |
void screen_draw_point(double sx, double sy) { | |
framebuffer* fb = draw_getfb(); | |
/* map center-origin screen coords to pixels. | |
* Deliberately using yres for both of these */ | |
draw_point( (0.5+sx)*fb->vinfo.yres, (0.5+sy)*fb->vinfo.yres ); | |
//draw_line( (0.5+sx)*640, (0.5+sy)*480, 0, 0 ); | |
} | |
void demo_rainbow(framebuffer* fb) { | |
for(int y=0; y<120; y++) { | |
for(int x=0; x<fb->width; x++) { | |
float alpha = y<20?1.f:1.f-((y-20)/100.f); | |
ARGB_color color = get_rainbow((float)x/(float)fb->width, alpha); | |
fb_blend_over(fb, x, y, color); | |
} | |
} | |
} | |
ARGB_color get_rainbow(float percent, float alpha) { | |
uint8_t red, green, blue; | |
float redf, greenf, bluef; | |
redf = 0.0; greenf = 0.0; bluef = 0.0; | |
double band = 0; | |
double hue = modf(percent*6.0, &band); | |
switch((int)band%6) { | |
case 0: | |
redf = 1.f; greenf = hue; | |
break; | |
case 1: | |
redf = 1.f-hue; greenf = 1.f; | |
break; | |
case 2: | |
greenf = 1.f; bluef = hue; | |
break; | |
case 3: | |
greenf = 1.f-hue; bluef = 1.f; | |
break; | |
case 4: | |
bluef = 1.f; redf = hue; | |
break; | |
case 5: | |
bluef = 1.f-hue; redf = 1.f; | |
break; | |
} | |
red = (uint8_t)(redf*255); | |
green = (uint8_t)(greenf*255); | |
blue = (uint8_t)(bluef*255); | |
return (uint8_t)(alpha*255)<<24 | red<<16 | green<<8 | blue; | |
} |
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
#ifndef _MAIN_H | |
#define _MAIN_H | |
#include <stdio.h> | |
#include <termios.h> | |
#include <unistd.h> | |
#include "framebuffer.h" | |
#include "draw.h" | |
/* Main.h */ | |
#define HALF_PI 1.57079632679 | |
typedef struct { | |
double xpos; | |
double ypos; | |
double zpos; | |
double yaw; | |
double pitch; | |
double fov; | |
double distort; | |
} camera3d; | |
void demo_rainbow(framebuffer* fb); | |
ARGB_color get_rainbow(float percent, float alpha); | |
void screen_draw_point(double sx, double sy); | |
void point_3d(double wx, double wy, double wz, camera3d cam); | |
void draw_3d(double[], camera3d cam); | |
void test_render(camera3d cam); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment