Created
January 12, 2017 00:16
-
-
Save Madsy/004a764b1453c8fcc68cf086b7bb4099 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 <cmath> | |
#include <vector> | |
#include <SDL/SDL.h> | |
#include <IL/il.h> | |
#include <math.h> | |
const float PI = 3.14159265359f; | |
typedef struct { | |
unsigned int id; | |
int width; | |
int height; | |
std::vector<unsigned char> pixels; | |
} Texture2D; | |
const int FRAMEBUFFER_WIDTH = 1280; | |
const int FRAMEBUFFER_HEIGHT = 720; | |
unsigned char* framebuffer = nullptr; | |
Texture2D* texture_ptr = nullptr; | |
typedef struct { | |
float x; | |
float y; | |
} Point2f; | |
typedef struct { | |
int x; | |
int y; | |
} Point2i; | |
static void swap_int(int* a, int* b){ | |
int tmp = *a; | |
*a = *b; | |
*b = tmp; | |
} | |
static void swap_float(float* a, float* b){ | |
float tmp = *a; | |
*a = *b; | |
*b = tmp; | |
} | |
static void swap_point2f(Point2f* a, Point2f* b){ | |
Point2f tmp = *a; | |
*a = *b; | |
*b = tmp; | |
} | |
Point2f rotate(Point2f* v, float angle){ | |
float M[4]; | |
Point2f vP; | |
M[0] = std::cos(angle/180.0f*PI); | |
M[1] = std::sin(angle/180.0f*PI); | |
M[2] = -std::sin(angle/180.0f*PI); | |
M[3] = std::cos(angle/180.0f*PI); | |
vP.x = M[0]*v->x + M[1]*v->y; | |
vP.y = M[2]*v->x + M[3]*v->y; | |
return vP; | |
} | |
static void blitPixel(int x, int y, | |
unsigned char r, | |
unsigned char g, | |
unsigned char b, | |
unsigned char a){ | |
if(!a) return; | |
framebuffer[(x + y * FRAMEBUFFER_WIDTH)*4 + 0] = r; //red | |
framebuffer[(x + y * FRAMEBUFFER_WIDTH)*4 + 1] = g; //green | |
framebuffer[(x + y * FRAMEBUFFER_WIDTH)*4 + 2] = b; //blue | |
framebuffer[(x + y * FRAMEBUFFER_WIDTH)*4 + 3] = 255; //alpha or unused | |
} | |
void drawtriangle(Point2f v1, Point2f v2, Point2f v3, Point2f t1, Point2f t2, Point2f t3) { | |
Point2f delta1, delta2, delta3; | |
Point2f deltaT1, deltaT2, deltaT3; | |
float slope1, slope2, slope3; | |
float slopeU1, slopeU2, slopeU3; | |
float slopeV1, slopeV2, slopeV3; | |
float xAccum1, xAccum2; | |
float uAccum1, uAccum2; | |
float vAccum1, vAccum2; | |
int yStart, yEnd; | |
int xStart, xEnd; | |
float uStart, uEnd; | |
float vStart, vEnd; | |
//sort vertices by increasing y | |
if(v1.y > v2.y) { | |
swap_point2f(&v1, &v2); | |
swap_point2f(&t1, &t2); | |
} | |
if(v2.y > v3.y) { | |
swap_point2f(&v2, &v3); | |
swap_point2f(&t2, &t3); | |
} | |
if(v1.y > v2.y) { | |
swap_point2f(&v1, &v2); | |
swap_point2f(&t1, &t2); | |
} | |
delta1.x = v3.x - v1.x; | |
delta1.y = v3.y - v1.y; | |
delta2.x = v2.x - v1.x; | |
delta2.y = v2.y - v1.y; | |
delta3.x = v3.x - v2.x; | |
delta3.y = v3.y - v2.y; | |
deltaT1.x = t3.x - t1.x; | |
deltaT1.y = t3.y - t1.y; | |
deltaT2.x = t2.x - t1.x; | |
deltaT2.y = t2.y - t1.y; | |
deltaT3.x = t3.x - t2.x; | |
deltaT3.y = t3.y - t2.y; | |
slope1 = slope2 = slope3 = 0; | |
slopeU1 = slopeU2 = slopeU3 = 0; | |
slopeV1 = slopeV2 = slopeV3 = 0; | |
//Rise over run for each edge | |
//We know that all the deltas are 0 or greater, because we sorted | |
//the points before | |
if(delta1.y > 0) { | |
slope1 = delta1.x / delta1.y; | |
slopeU1 = deltaT1.x / delta1.y; | |
slopeV1 = deltaT1.y / delta1.y; | |
} | |
if(delta2.y > 0) { | |
slope2 = delta2.x / delta2.y; | |
slopeU2 = deltaT2.x / delta2.y; | |
slopeV2 = deltaT2.y / delta2.y; | |
} | |
if(delta3.y > 0) { | |
slope3 = delta3.x / delta3.y; | |
slopeU3 = deltaT3.x / delta3.y; | |
slopeV3 = deltaT3.y / delta3.y; | |
} | |
//Render top part of triangle | |
yStart = (int)v1.y; | |
yEnd = (int)v2.y; | |
xAccum1 = v1.x; | |
xAccum2 = v1.x; | |
uAccum1 = t1.x; | |
uAccum2 = t1.x; | |
vAccum1 = t1.y; | |
vAccum2 = t1.y; | |
for(; yStart < yEnd; yStart++){ | |
float xDelta, uDelta, vDelta, uSlope, vSlope; | |
xStart = (int)xAccum1; | |
xEnd = (int)xAccum2; | |
uStart = uAccum1; | |
uEnd = uAccum2; | |
vStart = vAccum1; | |
vEnd = vAccum2; | |
//swap if middle point is on the 'wrong' side | |
if(xStart > xEnd){ | |
swap_int(&xStart, &xEnd); | |
swap_float(&uStart, &uEnd); | |
swap_float(&vStart, &vEnd); | |
} | |
//the length of the horisontal scanline | |
//this is the positive length of the "ideal" triangle, not the number of pixels! | |
xDelta = xEnd - xStart; | |
//the horisontal delta for U and V | |
uDelta = uEnd - uStart; | |
vDelta = vEnd - vStart; | |
uSlope = vSlope = 0.0f; | |
//the horisontal slopes for U and V | |
if(xDelta){ | |
uSlope = uDelta / xDelta; | |
vSlope = vDelta / xDelta; | |
} | |
for(; xStart < xEnd; xStart++){ | |
bool xTest = (xStart > 0) && (xStart < FRAMEBUFFER_WIDTH); | |
bool yTest = (yStart > 0) && (yStart < FRAMEBUFFER_HEIGHT); | |
if(xTest && yTest){ | |
int U = uStart * texture_ptr->width; | |
int V = vStart * texture_ptr->height; | |
int UVindex = U + V * texture_ptr->width; | |
unsigned char r = texture_ptr->pixels[UVindex*4 + 0]; | |
unsigned char g = texture_ptr->pixels[UVindex*4 + 1]; | |
unsigned char b = texture_ptr->pixels[UVindex*4 + 2]; | |
unsigned char a = texture_ptr->pixels[UVindex*4 + 3]; | |
blitPixel(xStart, yStart, r,g,b,a); | |
} | |
uStart += uSlope; | |
vStart += vSlope; | |
} | |
xAccum1 += slope1; | |
xAccum2 += slope2; | |
uAccum1 += slopeU1; | |
uAccum2 += slopeU2; | |
vAccum1 += slopeV1; | |
vAccum2 += slopeV2; | |
} | |
//render bottom part of triangle | |
yStart = (int)v2.y; | |
yEnd = (int)v3.y; | |
xAccum1 = v2.x; | |
xAccum2 = v1.x + slope1*delta2.y; | |
uAccum1 = t2.x; | |
uAccum2 = t1.x + slopeU1*delta2.y; | |
vAccum1 = t2.y; | |
vAccum2 = t1.y + slopeV1*delta2.y; | |
for(; yStart < yEnd; yStart++){ | |
float xDelta, uDelta, vDelta, uSlope, vSlope; | |
xStart = (int)xAccum1; | |
xEnd = (int)xAccum2; | |
uStart = uAccum1; | |
uEnd = uAccum2; | |
vStart = vAccum1; | |
vEnd = vAccum2; | |
//swap if middle point is on the 'wrong' side | |
if(xStart > xEnd){ | |
swap_int(&xStart, &xEnd); | |
swap_float(&uStart, &uEnd); | |
swap_float(&vStart, &vEnd); | |
} | |
//the length of the horisontal scanline | |
//this is the positive length of the "ideal" triangle, not the number of pixels! | |
xDelta = xEnd - xStart; | |
//the horisontal delta for U and V | |
uDelta = uEnd - uStart; | |
vDelta = vEnd - vStart; | |
uSlope = vSlope = 0.0f; | |
//the horisontal slopes for U and V | |
if(xDelta){ | |
uSlope = uDelta / xDelta; | |
vSlope = vDelta / xDelta; | |
} | |
for(; xStart < xEnd; xStart++){ | |
bool xTest = (xStart > 0) && (xStart < FRAMEBUFFER_WIDTH); | |
bool yTest = (yStart > 0) && (yStart < FRAMEBUFFER_HEIGHT); | |
if(xTest && yTest){ | |
int U = uStart * texture_ptr->width; | |
int V = vStart * texture_ptr->height; | |
int UVindex = U + V * texture_ptr->width; | |
unsigned char r = texture_ptr->pixels[UVindex*4 + 0]; | |
unsigned char g = texture_ptr->pixels[UVindex*4 + 1]; | |
unsigned char b = texture_ptr->pixels[UVindex*4 + 2]; | |
unsigned char a = texture_ptr->pixels[UVindex*4 + 3]; | |
blitPixel(xStart, yStart, r,g,b,a); | |
} | |
uStart += uSlope; | |
vStart += vSlope; | |
} | |
xAccum1 += slope3; | |
xAccum2 += slope1; | |
uAccum1 += slopeU3; | |
uAccum2 += slopeU1; | |
vAccum1 += slopeV3; | |
vAccum2 += slopeV1; | |
} | |
}; | |
int main(int argc, char* argv[]){ | |
SDL_Event ev; | |
SDL_Surface* s; | |
Texture2D textures[5]; | |
const char* texture_names[5] = { | |
"F.png", | |
"l.png", | |
"e.png", | |
"c.png", | |
"k.png" | |
}; | |
bool running = true; | |
float w = FRAMEBUFFER_WIDTH; | |
float h = FRAMEBUFFER_HEIGHT; | |
float wh = w*0.5f; | |
float hh = h*0.5f; | |
Point2f v1,v2,v3,v4; | |
Point2f t1,t2,t3,t4; | |
float xSizeHalf = 64.0f; | |
float ySizeHalf = 64.0f; | |
v1.x = -xSizeHalf; v1.y = -ySizeHalf; | |
v2.x = -xSizeHalf; v2.y = ySizeHalf; | |
v3.x = xSizeHalf; v3.y = ySizeHalf; | |
v4.x = xSizeHalf; v4.y = -ySizeHalf; | |
t1.x = 0.0f; t1.y = 0.0; | |
t2.x = 0.0f; t2.y = 1.0; | |
t3.x = 1.0f; t3.y = 1.0; | |
t4.x = 1.0f; t4.y = 0.0; | |
ilInit(); | |
SDL_Init(SDL_INIT_VIDEO); | |
s = SDL_SetVideoMode(FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, 32, SDL_SWSURFACE); | |
if(!s){ | |
SDL_Quit(); | |
return 1; | |
} | |
framebuffer = (unsigned char*)s->pixels; | |
for(int i = 0; i < 5; i++){ | |
ilGenImages(1, &textures[i].id); | |
ilBindImage(textures[i].id); | |
if(!ilLoadImage(texture_names[i])){ | |
return 2; | |
} | |
textures[i].width = ilGetInteger(IL_IMAGE_WIDTH); | |
textures[i].height = ilGetInteger(IL_IMAGE_HEIGHT); | |
textures[i].pixels.resize(textures[i].width*textures[i].height*4); | |
ilCopyPixels(0,0,0,textures[i].width, textures[i].height, 1, IL_RGBA, IL_UNSIGNED_BYTE, &textures[i].pixels[0]); | |
ilDeleteImages(1,&textures[i].id); | |
} | |
while(running){ | |
while(SDL_PollEvent(&ev)){ | |
switch(ev.type){ | |
case SDL_KEYDOWN: | |
case SDL_QUIT: | |
running = false; | |
break; | |
default: | |
break; | |
} | |
} | |
float t = (float)SDL_GetTicks() * 0.001f; | |
SDL_FillRect(s, nullptr, 0x00000000); | |
Point2f v1c,v2c,v3c,v4c; | |
Point2f t1c,t2c,t3c,t4c; | |
for(int i = 0; i < 5; i++){ | |
float xOffset = wh + (xSizeHalf*2)*(i-2); | |
v1c = rotate(&v1, 45.0f * t); | |
v2c = rotate(&v2, 45.0f * t); | |
v3c = rotate(&v3, 45.0f * t); | |
v4c = rotate(&v4, 45.0f * t); | |
t1c = t1; | |
t2c = t2; | |
t3c = t3; | |
t4c = t4; | |
v1c.x += xOffset; v1c.y += hh; | |
v2c.x += xOffset; v2c.y += hh; | |
v3c.x += xOffset; v3c.y += hh; | |
v4c.x += xOffset; v4c.y += hh; | |
texture_ptr = &textures[i]; | |
drawtriangle(v1c, v2c, v3c, t1c, t2c, t3c); | |
drawtriangle(v1c, v3c, v4c, t1c, t3c, t4c); | |
} | |
SDL_UpdateRect(s, 0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT); | |
} | |
SDL_Quit(); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment