Last active
April 8, 2023 08:49
-
-
Save joastbg/2c25b4062afc2dc128978ce7a907cb58 to your computer and use it in GitHub Desktop.
OpenGL 2D
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 <cstdlib> | |
#include <iostream> | |
#include <cstdio> | |
#include <cmath> | |
#include <thread> | |
#include <string> | |
#include <chrono> | |
#include <GL/glut.h> | |
#include <GL/glu.h> | |
#include <GL/gl.h> | |
#include <math.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
struct Vec { // Usage: time ./smallpt 5000 && xv image.ppm | |
double x, y, z; // position, also color (r,g,b) | |
Vec(double x_=0, double y_=0, double z_=0){ x=x_; y=y_; z=z_; } | |
Vec operator+(const Vec &b) const { return Vec(x+b.x,y+b.y,z+b.z); } | |
Vec operator-(const Vec &b) const { return Vec(x-b.x,y-b.y,z-b.z); } | |
Vec operator*(double b) const { return Vec(x*b,y*b,z*b); } | |
Vec mult(const Vec &b) const { return Vec(x*b.x,y*b.y,z*b.z); } | |
Vec& norm(){ return *this = *this * (1/sqrt(x*x+y*y+z*z)); } | |
double dot(const Vec &b) const { return x*b.x+y*b.y+z*b.z; } // cross: | |
Vec operator%(Vec&b){return Vec(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);} | |
}; | |
struct Ray { Vec o, d; Ray(Vec o_, Vec d_) : o(o_), d(d_) {} }; | |
enum Refl_t { DIFF, SPEC, REFR }; // material types, used in radiance() | |
struct Sphere { | |
double rad; // radius | |
Vec p, e, c; // position, emission, color | |
Refl_t refl; // reflection type (DIFFuse, SPECular, REFRactive) | |
Sphere(double rad_, Vec p_, Vec e_, Vec c_, Refl_t refl_): | |
rad(rad_), p(p_), e(e_), c(c_), refl(refl_) {} | |
double intersect(const Ray &r) const { // returns distance, 0 if nohit | |
Vec op = p-r.o; // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0 | |
double t, eps=1e-4, b=op.dot(r.d), det=b*b-op.dot(op)+rad*rad; | |
if (det<0) return 0; else det=sqrt(det); | |
return (t=b-det)>eps ? t : ((t=b+det)>eps ? t : 0); | |
} | |
}; | |
Sphere spheres[] = {//Scene: radius, position, emission, color, material | |
Sphere(1e5, Vec( 1e5+1,40.8,81.6), Vec(),Vec(.75,.25,.25),DIFF),//Left | |
Sphere(1e5, Vec(-1e5+99,40.8,81.6),Vec(),Vec(.25,.25,.75),DIFF),//Rght | |
Sphere(1e5, Vec(50,40.8, 1e5), Vec(),Vec(.75,.75,.75),DIFF),//Back | |
Sphere(1e5, Vec(50,40.8,-1e5+170), Vec(),Vec(), DIFF),//Frnt | |
Sphere(1e5, Vec(50, 1e5, 81.6), Vec(),Vec(.75,.75,.75),DIFF),//Botm | |
Sphere(1e5, Vec(50,-1e5+81.6,81.6),Vec(),Vec(.75,.75,.75),DIFF),//Top | |
Sphere(16.5,Vec(27,16.5,47), Vec(),Vec(1,1,1)*.999, SPEC),//Mirr | |
Sphere(16.5,Vec(73,16.5,78), Vec(),Vec(1,1,1)*.999, REFR),//Glas | |
Sphere(600, Vec(50,681.6-.27,81.6),Vec(12,12,12), Vec(), DIFF) //Lite | |
}; | |
inline double clamp(double x){ return x<0 ? 0 : x>1 ? 1 : x; } | |
inline int toInt(double x){ return int(pow(clamp(x),1/2.2)*255+.5); } | |
inline bool intersect(const Ray &r, double &t, int &id){ | |
double n=sizeof(spheres)/sizeof(Sphere), d, inf=t=1e20; | |
for(int i=int(n);i--;) if((d=spheres[i].intersect(r))&&d<t){t=d;id=i;} | |
return t<inf; | |
} | |
Vec radiance(const Ray &r, int depth, unsigned short *Xi){ | |
double t; // distance to intersection | |
int id=0; // id of intersected object | |
if (!intersect(r, t, id)) return Vec(); // if miss, return black | |
const Sphere &obj = spheres[id]; // the hit object | |
Vec x=r.o+r.d*t, n=(x-obj.p).norm(), nl=n.dot(r.d)<0?n:n*-1, f=obj.c; | |
double p = f.x>f.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // max refl | |
if (++depth>5) if (erand48(Xi)<p) f=f*(1/p); else return obj.e; //R.R. | |
if (obj.refl == DIFF){ // Ideal DIFFUSE reflection | |
double r1=2*M_PI*erand48(Xi), r2=erand48(Xi), r2s=sqrt(r2); | |
Vec w=nl, u=((fabs(w.x)>.1?Vec(0,1):Vec(1))%w).norm(), v=w%u; | |
Vec d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1-r2)).norm(); | |
return obj.e + f.mult(radiance(Ray(x,d),depth,Xi)); | |
} else if (obj.refl == SPEC) // Ideal SPECULAR reflection | |
return obj.e + f.mult(radiance(Ray(x,r.d-n*2*n.dot(r.d)),depth,Xi)); | |
Ray reflRay(x, r.d-n*2*n.dot(r.d)); // Ideal dielectric REFRACTION | |
bool into = n.dot(nl)>0; // Ray from outside going in? | |
double nc=1, nt=1.5, nnt=into?nc/nt:nt/nc, ddn=r.d.dot(nl), cos2t; | |
if ((cos2t=1-nnt*nnt*(1-ddn*ddn))<0) // Total internal reflection | |
return obj.e + f.mult(radiance(reflRay,depth,Xi)); | |
Vec tdir = (r.d*nnt - n*((into?1:-1)*(ddn*nnt+sqrt(cos2t)))).norm(); | |
double a=nt-nc, b=nt+nc, R0=a*a/(b*b), c = 1-(into?-ddn:tdir.dot(n)); | |
double Re=R0+(1-R0)*c*c*c*c*c,Tr=1-Re,P=.25+.5*Re,RP=Re/P,TP=Tr/(1-P); | |
return obj.e + f.mult(depth>2 ? (erand48(Xi)<P ? // Russian roulette | |
radiance(reflRay,depth,Xi)*RP:radiance(Ray(x,tdir),depth,Xi)*TP) : | |
radiance(reflRay,depth,Xi)*Re+radiance(Ray(x,tdir),depth,Xi)*Tr); | |
} | |
using namespace std; // make std accessible | |
GLint TIMER_DELAY = 100; // timer delay (10 seconds) | |
GLfloat RED_RGB[] = {1.0, 0.0, 0.0}; // drawing colors | |
GLfloat BLUE_RGB[] = {0.0, 0.0, 1.0}; | |
static bool isReversed = false; // draw reversed colors? | |
void myReshape(int w, int h) { | |
cout << "MyReshape called width=" << w << " height=" << h << endl; | |
glViewport (0, 0, w, h); // update the viewport | |
glMatrixMode(GL_PROJECTION); // update projection | |
glLoadIdentity(); | |
gluOrtho2D(0.0, 1.0, 0.0, 1.0); // map unit square to viewport | |
glMatrixMode(GL_MODELVIEW); | |
glutPostRedisplay(); // request redisplay | |
} | |
struct rgbf {float r; float g; float b;}; | |
float* pixels; | |
unsigned int window_width = 800, window_height = 600; | |
int w=window_width, h=window_height, samps = 100; | |
const int size=window_width*window_height; | |
// draw diamond and rectangle | |
void drawObjects() { | |
//for (int i=0; i<w*h; i++) | |
//fprintf(f,"%d %d %d ", toInt(c[i].x), toInt(c[i].y), toInt(c[i].z)); | |
//for (int i=0; i<w*h; i++) { | |
//for(int i=0;i<size;i+=3) { | |
//pixels[i] = c[i].x; | |
//pixels[i+1] = c[i].y; | |
//pixels[i+2] = c[i].z; | |
//} | |
} | |
void myDisplay(void) { | |
glClearColor(0.0, 0.0, 0.0, 1.0); | |
glClear(GL_COLOR_BUFFER_BIT); | |
glDrawPixels(window_width, window_height, GL_RGB, GL_FLOAT, pixels); | |
glutSwapBuffers(); | |
} | |
void myTimer(int id) { | |
isReversed = !isReversed; | |
glutPostRedisplay(); | |
glutTimerFunc(TIMER_DELAY, myTimer, 0); | |
} | |
void myMouse(int b, int s, int x, int y) { | |
if (s == GLUT_DOWN) { | |
cout << "Mouse click detected at coordinates x=" | |
<< x << " and y=" << y << endl; | |
if (b == GLUT_LEFT_BUTTON) { | |
isReversed = !isReversed; | |
cout << "Left mouse click. Reversing colors." << endl; | |
glutPostRedisplay(); | |
} | |
} | |
} | |
void myKeyboard(unsigned char c, int x, int y) { | |
switch (c) { | |
case 'q': | |
exit(0); | |
break; | |
default: | |
cout << "Hit q to quit. All other characters ignored" << endl; | |
break; | |
} | |
} | |
void task1(string msg) | |
{ | |
Ray cam(Vec(50,52,295.6), Vec(0,-0.042612,-1).norm()); // cam pos, dir | |
Vec cx=Vec(w*.5135/h), cy=(cx%cam.d).norm()*.5135, r, *c=new Vec[w*h]; | |
for (int y=h/2; y<h; y++){ // Loop over image rows | |
for (unsigned short x=0, Xi[3]={0,0,y*y*y}; x<w; x++) // Loop cols | |
for (int sy=0, i=(h-y-1)*w+x; sy<2; sy++) // 2x2 subpixel rows | |
for (int sx=0; sx<2; sx++, r=Vec()){ // 2x2 subpixel cols | |
for (int s=0; s<samps; s++){ | |
double r1=2*erand48(Xi), dx=r1<1 ? sqrt(r1)-1: 1-sqrt(2-r1); | |
double r2=2*erand48(Xi), dy=r2<1 ? sqrt(r2)-1: 1-sqrt(2-r2); | |
Vec d = cx*( ( (sx+.5 + dx)/2 + x)/w - .5) + | |
cy*( ( (sy+.5 + dy)/2 + y)/h - .5) + cam.d; | |
r = r + radiance(Ray(cam.o+d*140,d.norm()),0,Xi)*(1./samps); | |
}// Camera rays are pushed ^^^^^ forward to start in interior | |
c[i] = c[i] + Vec(clamp(r.x),clamp(r.y),clamp(r.z))*.25; | |
pixels[w*h*3-i*3] = c[i].x; | |
pixels[w*h*3-i*3+1] = c[i].y; | |
pixels[w*h*3-i*3+2] = c[i].z; | |
} | |
glutPostRedisplay(); | |
} | |
} | |
void task2(string msg) | |
{ | |
Ray cam(Vec(50,52,295.6), Vec(0,-0.042612,-1).norm()); // cam pos, dir | |
Vec cx=Vec(w*.5135/h), cy=(cx%cam.d).norm()*.5135, r, *c=new Vec[w*h]; | |
for (int y=0; y<h/2; y++){ // Loop over image rows | |
for (unsigned short x=0, Xi[3]={0,0,y*y*y}; x<w; x++) // Loop cols | |
for (int sy=0, i=(h-y-1)*w+x; sy<2; sy++) // 2x2 subpixel rows | |
for (int sx=0; sx<2; sx++, r=Vec()){ // 2x2 subpixel cols | |
for (int s=0; s<samps; s++){ | |
double r1=2*erand48(Xi), dx=r1<1 ? sqrt(r1)-1: 1-sqrt(2-r1); | |
double r2=2*erand48(Xi), dy=r2<1 ? sqrt(r2)-1: 1-sqrt(2-r2); | |
Vec d = cx*( ( (sx+.5 + dx)/2 + x)/w - .5) + | |
cy*( ( (sy+.5 + dy)/2 + y)/h - .5) + cam.d; | |
r = r + radiance(Ray(cam.o+d*140,d.norm()),0,Xi)*(1./samps); | |
}// Camera rays are pushed ^^^^^ forward to start in interior | |
c[i] = c[i] + Vec(clamp(r.x),clamp(r.y),clamp(r.z))*.25; | |
pixels[w*h*3-i*3] = c[i].x; | |
pixels[w*h*3-i*3+1] = c[i].y; | |
pixels[w*h*3-i*3+2] = c[i].z; | |
} | |
glutPostRedisplay(); | |
} | |
} | |
int main(int argc, char** argv) | |
{ | |
glutInit(&argc, argv); // OpenGL initializations | |
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);// double buffering and RGB | |
glutInitWindowSize(800, 600); // create a 400x400 window | |
glutInitWindowPosition(0, 0); // ...in the upper left | |
glutCreateWindow(argv[0]); // create the window | |
std::thread t1(task1, "Hello"); | |
std::thread t2(task2, "Hello"); | |
pixels = new float[size*3]; | |
glutDisplayFunc(myDisplay); // setup callbacks | |
glutReshapeFunc(myReshape); | |
//glutMouseFunc(myMouse); | |
//glutKeyboardFunc(myKeyboard); | |
glutTimerFunc(TIMER_DELAY, myTimer, 0); | |
glutMainLoop(); // start it running | |
// Makes the main thread wait for the new thread to finish execution, therefore blocks its own execution. | |
t1.join(); | |
t2.join(); | |
return 0; // ANSI C expects this | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment