Compare commits
8
Commits
deb16eeef7
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a5b1292ee | ||
|
|
36e12d1e90 | ||
|
|
aad02e522d | ||
|
|
8f09415b37 | ||
|
|
d1b558a554 | ||
|
|
acfb883f66 | ||
|
|
ede4f6235a | ||
|
|
0003c74f3b |
No files matched your search
@@ -2,9 +2,7 @@ configure do
|
|||||||
check_cxx_compiler
|
check_cxx_compiler
|
||||||
check_program "flex"
|
check_program "flex"
|
||||||
check_program "bison"
|
check_program "bison"
|
||||||
check_lib ":libfl.a"
|
|
||||||
check_lib "pthread"
|
check_lib "pthread"
|
||||||
check_lib "freeimage"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
env do |env|
|
env do |env|
|
||||||
|
|||||||
+26
-27
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "Scene.h"
|
#include "Scene.h"
|
||||||
#include "Light.h"
|
#include "Light.h"
|
||||||
|
#include "util/stb_image.h"
|
||||||
#include "parser/parser.h"
|
#include "parser/parser.h"
|
||||||
#include "parser/nodes.h"
|
#include "parser/nodes.h"
|
||||||
#include "util/Polygon.h"
|
#include "util/Polygon.h"
|
||||||
@@ -347,19 +348,23 @@ refptr<Material> Scene::processMaterial(refptr<Node> node)
|
|||||||
else if ( typeid(**it) == typeid(TextureNode) )
|
else if ( typeid(**it) == typeid(TextureNode) )
|
||||||
{
|
{
|
||||||
string filename = (*it)->getString();
|
string filename = (*it)->getString();
|
||||||
FIBITMAP * fib = NULL;
|
Texture * texture = NULL;
|
||||||
if (m_textures.find(filename) != m_textures.end())
|
if (m_textures.find(filename) != m_textures.end())
|
||||||
{
|
{
|
||||||
/* texture already loaded */
|
/* texture already loaded */
|
||||||
fib = m_textures[filename];
|
texture = m_textures[filename];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fib = loadTexture((*it)->getString());
|
texture = loadTexture(filename);
|
||||||
|
if (texture != NULL)
|
||||||
|
{
|
||||||
|
m_textures[filename] = texture;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (fib != NULL)
|
if (texture != NULL)
|
||||||
{
|
{
|
||||||
material->setTexture(fib);
|
material->setTexture(texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -811,30 +816,24 @@ void Scene::processShapeDefinition(refptr<Node> node)
|
|||||||
m_transforms.pop();
|
m_transforms.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
FIBITMAP * Scene::loadTexture(const std::string & filename)
|
Texture * Scene::loadTexture(const std::string & filename)
|
||||||
{
|
{
|
||||||
FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filename.c_str(), 0);
|
int width = 0;
|
||||||
if (fif == FIF_UNKNOWN)
|
int height = 0;
|
||||||
|
int channels = 0;
|
||||||
|
/* request 4 channels so the data is always tightly packed RGBA */
|
||||||
|
unsigned char * data = stbi_load(filename.c_str(), &width, &height,
|
||||||
|
&channels, 4);
|
||||||
|
if (data == NULL)
|
||||||
{
|
{
|
||||||
fif = FreeImage_GetFIFFromFilename(filename.c_str());
|
cerr << "Error: image \"" << filename << "\" could not be loaded: "
|
||||||
if (fif == FIF_UNKNOWN)
|
<< stbi_failure_reason() << endl;
|
||||||
{
|
|
||||||
cerr << "Error: couldn't determine image format for \""
|
|
||||||
<< filename << "\"" << endl;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!FreeImage_FIFSupportsReading(fif))
|
|
||||||
{
|
|
||||||
cerr << "Error: image format of \"" << filename
|
|
||||||
<< "\" does not support reading" << endl;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
FIBITMAP * fib = FreeImage_Load(fif, filename.c_str(), 0);
|
Texture * texture = new Texture;
|
||||||
if (fib == NULL)
|
texture->width = width;
|
||||||
{
|
texture->height = height;
|
||||||
cerr << "Error: image \"" << filename << "\" could not be loaded"
|
texture->channels = 4;
|
||||||
<< endl;
|
texture->data = data;
|
||||||
}
|
return texture;
|
||||||
return fib;
|
|
||||||
}
|
}
|
||||||
+5
-4
@@ -7,11 +7,11 @@
|
|||||||
#include <utility> /* pair */
|
#include <utility> /* pair */
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm> /* sort() */
|
#include <algorithm> /* sort() */
|
||||||
#include <functional> /* binary_function */
|
|
||||||
#include <typeinfo> /* typeid operator support */
|
#include <typeinfo> /* typeid operator support */
|
||||||
|
|
||||||
#include "Scene.h"
|
#include "Scene.h"
|
||||||
#include "BMP.h"
|
#include "BMP.h"
|
||||||
|
#include "util/stb_image.h"
|
||||||
#include "util/Color.h"
|
#include "util/Color.h"
|
||||||
#include "shapes/Shape.h"
|
#include "shapes/Shape.h"
|
||||||
#include "Light.h"
|
#include "Light.h"
|
||||||
@@ -75,12 +75,13 @@ Scene::Scene(const map<string, const char *> & options,
|
|||||||
|
|
||||||
Scene::~Scene()
|
Scene::~Scene()
|
||||||
{
|
{
|
||||||
/* clean up any textures loaded with freeimage */
|
/* clean up any textures loaded with stb_image */
|
||||||
for (std::map< std::string, FIBITMAP * >::iterator it = m_textures.begin();
|
for (std::map< std::string, Texture * >::iterator it = m_textures.begin();
|
||||||
it != m_textures.end();
|
it != m_textures.end();
|
||||||
it++)
|
it++)
|
||||||
{
|
{
|
||||||
FreeImage_Unload(it->second);
|
stbi_image_free(it->second->data);
|
||||||
|
delete it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-4
@@ -8,8 +8,6 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
#include <FreeImage.h>
|
|
||||||
|
|
||||||
#include "util/refptr.h"
|
#include "util/refptr.h"
|
||||||
#include "util/Ray.h"
|
#include "util/Ray.h"
|
||||||
#include "util/Color.h"
|
#include "util/Color.h"
|
||||||
@@ -82,7 +80,7 @@ class Scene
|
|||||||
std::vector<ShapeRef> processForNode(refptr<Node> node);
|
std::vector<ShapeRef> processForNode(refptr<Node> node);
|
||||||
void processMaterialDefinition(refptr<Node> node);
|
void processMaterialDefinition(refptr<Node> node);
|
||||||
void processShapeDefinition(refptr<Node> node);
|
void processShapeDefinition(refptr<Node> node);
|
||||||
FIBITMAP * loadTexture(const std::string & filename);
|
Texture * loadTexture(const std::string & filename);
|
||||||
|
|
||||||
/* rendering parameters */
|
/* rendering parameters */
|
||||||
int m_width;
|
int m_width;
|
||||||
@@ -104,7 +102,7 @@ class Scene
|
|||||||
double m_sample_span;
|
double m_sample_span;
|
||||||
double m_half_sample_span;
|
double m_half_sample_span;
|
||||||
std::map< std::string, refptr<Material> > m_materials;
|
std::map< std::string, refptr<Material> > m_materials;
|
||||||
std::map< std::string, FIBITMAP * > m_textures;
|
std::map< std::string, Texture * > m_textures;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+117
-28
@@ -9,8 +9,10 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <FreeImage.h>
|
#include <pthread.h>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "Scene.h"
|
#include "Scene.h"
|
||||||
#include "distrib/distrib.h"
|
#include "distrib/distrib.h"
|
||||||
@@ -18,6 +20,111 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of contiguous pixels each worker thread claims at a time. Pulling
|
||||||
|
* work in small chunks (rather than whole rows) keeps the load balanced even
|
||||||
|
* when individual rows vary wildly in render cost, while keeping the claimed
|
||||||
|
* pixels contiguous so cache locality and dispatch overhead stay close to the
|
||||||
|
* row-based baseline. See benchmarks: 64 was the sweet spot.
|
||||||
|
*/
|
||||||
|
#define RENDER_CHUNK_SIZE 64
|
||||||
|
|
||||||
|
/*
|
||||||
|
* State shared by the local multithreaded renderer. Worker threads pull
|
||||||
|
* fixed-size chunks of pixels off a lock-free atomic cursor until the image
|
||||||
|
* is complete.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Scene * scene;
|
||||||
|
unsigned char * data;
|
||||||
|
int width;
|
||||||
|
int total_pixels;
|
||||||
|
std::atomic<int> next_pixel; /* dispatch cursor: next unclaimed pixel */
|
||||||
|
std::atomic<int> pixels_done; /* pixels finished, for progress */
|
||||||
|
std::atomic<int> last_permille; /* last tenth-of-a-percent printed */
|
||||||
|
} render_thread_state_t;
|
||||||
|
|
||||||
|
static void * render_thread(void * varg)
|
||||||
|
{
|
||||||
|
render_thread_state_t * state = (render_thread_state_t *) varg;
|
||||||
|
const int width = state->width;
|
||||||
|
const int total_pixels = state->total_pixels;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
/* atomically claim the next chunk of contiguous pixels */
|
||||||
|
int start = state->next_pixel.fetch_add(RENDER_CHUNK_SIZE,
|
||||||
|
std::memory_order_relaxed);
|
||||||
|
if (start >= total_pixels)
|
||||||
|
break;
|
||||||
|
int end = start + RENDER_CHUNK_SIZE;
|
||||||
|
if (end > total_pixels)
|
||||||
|
end = total_pixels;
|
||||||
|
|
||||||
|
for (int pixel = start; pixel < end; pixel++)
|
||||||
|
{
|
||||||
|
int y = pixel / width;
|
||||||
|
int x = pixel % width;
|
||||||
|
state->scene->renderPixel(x, y, &state->data[3 * pixel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* report progress without locking: of the threads that advance the
|
||||||
|
* tenth-of-a-percent counter, only the one that wins the update prints,
|
||||||
|
* so the display stays monotonic and free of interleaved output */
|
||||||
|
int done = state->pixels_done.fetch_add(end - start,
|
||||||
|
std::memory_order_relaxed)
|
||||||
|
+ (end - start);
|
||||||
|
int permille = (int) (1000L * done / total_pixels);
|
||||||
|
int prev = state->last_permille.load(std::memory_order_relaxed);
|
||||||
|
while (permille > prev)
|
||||||
|
{
|
||||||
|
if (state->last_permille.compare_exchange_weak(
|
||||||
|
prev, permille, std::memory_order_relaxed))
|
||||||
|
{
|
||||||
|
printf("\e[8D%2.1f%%", permille / 10.0);
|
||||||
|
fflush(stdout);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* prev reloaded by compare_exchange_weak; re-test permille > prev */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderThreaded(Scene & scene,
|
||||||
|
unsigned char * data,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int num_threads)
|
||||||
|
{
|
||||||
|
/* a non-positive override means auto-detect the available cores */
|
||||||
|
if (num_threads < 1)
|
||||||
|
{
|
||||||
|
num_threads = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if (num_threads < 1)
|
||||||
|
num_threads = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
render_thread_state_t state;
|
||||||
|
state.scene = &scene;
|
||||||
|
state.data = data;
|
||||||
|
state.width = width;
|
||||||
|
state.total_pixels = width * height;
|
||||||
|
state.next_pixel.store(0, std::memory_order_relaxed);
|
||||||
|
state.pixels_done.store(0, std::memory_order_relaxed);
|
||||||
|
state.last_permille.store(0, std::memory_order_relaxed);
|
||||||
|
|
||||||
|
vector<pthread_t> threads(num_threads);
|
||||||
|
for (int i = 0; i < num_threads; i++)
|
||||||
|
pthread_create(&threads[i], NULL, render_thread, &state);
|
||||||
|
for (int i = 0; i < num_threads; i++)
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
|
||||||
|
printf("\e[8D");
|
||||||
|
}
|
||||||
|
|
||||||
void usage(const char * progname)
|
void usage(const char * progname)
|
||||||
{
|
{
|
||||||
cout << "Usage: " << progname << " [options] <scene-file>" << endl;
|
cout << "Usage: " << progname << " [options] <scene-file>" << endl;
|
||||||
@@ -30,6 +137,7 @@ void usage(const char * progname)
|
|||||||
cout << " -d|--max-depth <max-recursion-depth>" << endl;
|
cout << " -d|--max-depth <max-recursion-depth>" << endl;
|
||||||
cout << " -a|--ambient-occlusion <ambient-occlusion-level>" << endl;
|
cout << " -a|--ambient-occlusion <ambient-occlusion-level>" << endl;
|
||||||
cout << " -p|--preview (means -w400 -h300 -m1 -d8 -a0)" << endl;
|
cout << " -p|--preview (means -w400 -h300 -m1 -d8 -a0)" << endl;
|
||||||
|
cout << " -j|--threads <num-threads> (default: number of cores)" << endl;
|
||||||
cout << " --hosts <hosts-file>" << endl;
|
cout << " --hosts <hosts-file>" << endl;
|
||||||
exit(42);
|
exit(42);
|
||||||
}
|
}
|
||||||
@@ -92,6 +200,7 @@ int main(int argc, char * argv[])
|
|||||||
unsigned char * data = NULL;
|
unsigned char * data = NULL;
|
||||||
const char * output_file_name = "fart.bmp";
|
const char * output_file_name = "fart.bmp";
|
||||||
bool child = false;
|
bool child = false;
|
||||||
|
int num_threads = 0; /* 0 means auto-detect available cores */
|
||||||
|
|
||||||
static const struct option long_options[] = {
|
static const struct option long_options[] = {
|
||||||
{ "ambient-occlusion", required_argument, NULL, 'a' },
|
{ "ambient-occlusion", required_argument, NULL, 'a' },
|
||||||
@@ -102,6 +211,7 @@ int main(int argc, char * argv[])
|
|||||||
{ "field-of-view", required_argument, NULL, 'f' },
|
{ "field-of-view", required_argument, NULL, 'f' },
|
||||||
{ "max-depth", required_argument, NULL, 'd' },
|
{ "max-depth", required_argument, NULL, 'd' },
|
||||||
{ "preview", no_argument, NULL, 'p' },
|
{ "preview", no_argument, NULL, 'p' },
|
||||||
|
{ "threads", required_argument, NULL, 'j' },
|
||||||
{ "help", no_argument, NULL, 256 },
|
{ "help", no_argument, NULL, 256 },
|
||||||
{ "host", required_argument, NULL, 257 },
|
{ "host", required_argument, NULL, 257 },
|
||||||
{ "port", required_argument, NULL, 258 },
|
{ "port", required_argument, NULL, 258 },
|
||||||
@@ -110,7 +220,7 @@ int main(int argc, char * argv[])
|
|||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, "a:o:w:h:m:f:d:p",
|
while ((opt = getopt_long(argc, argv, "a:o:w:h:m:f:d:pj:",
|
||||||
long_options, &option_index)) != -1)
|
long_options, &option_index)) != -1)
|
||||||
{
|
{
|
||||||
switch (opt)
|
switch (opt)
|
||||||
@@ -156,6 +266,9 @@ int main(int argc, char * argv[])
|
|||||||
scene_options["max-depth"] = "8";
|
scene_options["max-depth"] = "8";
|
||||||
client_options.push_back("--preview");
|
client_options.push_back("--preview");
|
||||||
break;
|
break;
|
||||||
|
case 'j':
|
||||||
|
num_threads = atoi(optarg);
|
||||||
|
break;
|
||||||
case 256:
|
case 256:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
break;
|
break;
|
||||||
@@ -188,8 +301,6 @@ int main(int argc, char * argv[])
|
|||||||
|
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
FreeImage_Initialise(FALSE);
|
|
||||||
|
|
||||||
const char * filename = argv[optind];
|
const char * filename = argv[optind];
|
||||||
client_options.push_back(filename);
|
client_options.push_back(filename);
|
||||||
Scene scene(scene_options, filename);
|
Scene scene(scene_options, filename);
|
||||||
@@ -278,28 +389,8 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int total_pixels = height * width;
|
/* local multithreaded render; num_threads of 0 auto-detects cores */
|
||||||
int total_pixels_1000 = total_pixels / 1000;
|
renderThreaded(scene, data, width, height, num_threads);
|
||||||
if (total_pixels_1000 < 1)
|
|
||||||
total_pixels_1000 = 1;
|
|
||||||
int pixel_num = 0;
|
|
||||||
/* "sequential" version */
|
|
||||||
for (int i = 0; i < height; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < width; j++)
|
|
||||||
{
|
|
||||||
int pixel = i * width + j;
|
|
||||||
scene.renderPixel(j, i, &data[3 * pixel]);
|
|
||||||
pixel_num++;
|
|
||||||
if (pixel_num % total_pixels_1000 == 0)
|
|
||||||
{
|
|
||||||
double pct = 100.0 * pixel_num / (double) total_pixels;
|
|
||||||
printf("\e[8D%2.1f%%", pct);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("\e[8D");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gettimeofday(&after, NULL); /* stop timing */
|
gettimeofday(&after, NULL); /* stop timing */
|
||||||
@@ -338,8 +429,6 @@ int main(int argc, char * argv[])
|
|||||||
cout << endl;
|
cout << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeImage_DeInitialise();
|
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
%option nounput
|
%option nounput
|
||||||
|
%option noyywrap
|
||||||
%option bison-locations
|
%option bison-locations
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|||||||
@@ -19,11 +19,6 @@ extern FILE * yyin;
|
|||||||
|
|
||||||
void errFunc(const char * str, YYLTYPE * yyllocp);
|
void errFunc(const char * str, YYLTYPE * yyllocp);
|
||||||
|
|
||||||
int yywrap()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static refptr<Node> parsed_scene_node;
|
static refptr<Node> parsed_scene_node;
|
||||||
refptr<Scope> parser_scope;
|
refptr<Scope> parser_scope;
|
||||||
|
|
||||||
@@ -33,6 +28,12 @@ refptr<Scope> parser_scope;
|
|||||||
%locations
|
%locations
|
||||||
%define parse.error verbose
|
%define parse.error verbose
|
||||||
|
|
||||||
|
%initial-action {
|
||||||
|
/* Reference yynerrs so the generated parser does not warn that it is
|
||||||
|
set but never used; this grammar has no error-recovery rules. */
|
||||||
|
(void) yynerrs;
|
||||||
|
}
|
||||||
|
|
||||||
%token PLUS;
|
%token PLUS;
|
||||||
%token MINUS;
|
%token MINUS;
|
||||||
%token TIMES;
|
%token TIMES;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
#include "Shape.h"
|
#include "Shape.h"
|
||||||
#include <algorithm> /* sort() */
|
#include <algorithm> /* sort() */
|
||||||
#include <functional> /* binary_function */
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -28,9 +27,6 @@ void Shape::setMaterial(refptr<Material> material)
|
|||||||
}
|
}
|
||||||
|
|
||||||
class BoolIntersectionComparator
|
class BoolIntersectionComparator
|
||||||
: public std::binary_function<Shape::BoolIntersection,
|
|
||||||
Shape::BoolIntersection,
|
|
||||||
bool>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BoolIntersectionComparator(const Vector & refPoint)
|
BoolIntersectionComparator(const Vector & refPoint)
|
||||||
|
|||||||
+4
-5
@@ -2,8 +2,7 @@
|
|||||||
#ifndef MATERIAL_H
|
#ifndef MATERIAL_H
|
||||||
#define MATERIAL_H MATERIAL_H
|
#define MATERIAL_H MATERIAL_H
|
||||||
|
|
||||||
#include <FreeImage.h>
|
#include "Texture.h"
|
||||||
|
|
||||||
#include "Color.h"
|
#include "Color.h"
|
||||||
|
|
||||||
class Material
|
class Material
|
||||||
@@ -55,8 +54,8 @@ class Material
|
|||||||
void setTransparency(double t) { m_transparency = t; }
|
void setTransparency(double t) { m_transparency = t; }
|
||||||
double getTransparency() const { return m_transparency; }
|
double getTransparency() const { return m_transparency; }
|
||||||
|
|
||||||
void setTexture(FIBITMAP * fib) { m_texture = fib; }
|
void setTexture(Texture * texture) { m_texture = texture; }
|
||||||
FIBITMAP * getTexture() const { return m_texture; }
|
Texture * getTexture() const { return m_texture; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Color m_ambient_color;
|
Color m_ambient_color;
|
||||||
@@ -66,7 +65,7 @@ class Material
|
|||||||
double m_reflectance;
|
double m_reflectance;
|
||||||
double m_refraction;
|
double m_refraction;
|
||||||
double m_transparency;
|
double m_transparency;
|
||||||
FIBITMAP * m_texture;
|
Texture * m_texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
#ifndef TEXTURE_H
|
||||||
|
#define TEXTURE_H TEXTURE_H
|
||||||
|
|
||||||
|
/* A loaded image texture. Pixel data is stored as tightly packed RGBA
|
||||||
|
* bytes (4 channels) and is owned by this struct -- free it with
|
||||||
|
* stbi_image_free(). */
|
||||||
|
struct Texture
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int channels;
|
||||||
|
unsigned char * data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+17
-17
@@ -3,17 +3,18 @@
|
|||||||
#define REFPTR_H REFPTR_H
|
#define REFPTR_H REFPTR_H
|
||||||
|
|
||||||
#include <stdlib.h> /* NULL */
|
#include <stdlib.h> /* NULL */
|
||||||
|
#include <atomic> /* std::atomic */
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class refptr
|
class refptr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
refptr<T>();
|
refptr();
|
||||||
refptr<T>(T * ptr);
|
refptr(T * ptr);
|
||||||
refptr<T>(const refptr<T> & orig);
|
refptr(const refptr<T> & orig);
|
||||||
refptr<T> & operator=(const refptr<T> & orig);
|
refptr & operator=(const refptr<T> & orig);
|
||||||
refptr<T> & operator=(T * ptr);
|
refptr & operator=(T * ptr);
|
||||||
~refptr<T>();
|
~refptr();
|
||||||
T & operator*() const;
|
T & operator*() const;
|
||||||
T * operator->() const;
|
T * operator->() const;
|
||||||
bool isNull() const { return m_ptr == NULL; }
|
bool isNull() const { return m_ptr == NULL; }
|
||||||
@@ -25,7 +26,10 @@ class refptr
|
|||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
T * m_ptr;
|
T * m_ptr;
|
||||||
int * m_refCount;
|
/* reference count is atomic so that refptr copies may be made
|
||||||
|
* concurrently from multiple threads (e.g. the multithreaded
|
||||||
|
* renderer) without corrupting the count */
|
||||||
|
std::atomic<int> * m_refCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> refptr<T>::refptr()
|
template <typename T> refptr<T>::refptr()
|
||||||
@@ -37,8 +41,7 @@ template <typename T> refptr<T>::refptr()
|
|||||||
template <typename T> refptr<T>::refptr(T * ptr)
|
template <typename T> refptr<T>::refptr(T * ptr)
|
||||||
{
|
{
|
||||||
m_ptr = ptr;
|
m_ptr = ptr;
|
||||||
m_refCount = new int;
|
m_refCount = new std::atomic<int>(1);
|
||||||
*m_refCount = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> refptr<T>::refptr(const refptr<T> & orig)
|
template <typename T> refptr<T>::refptr(const refptr<T> & orig)
|
||||||
@@ -57,8 +60,7 @@ template <typename T> refptr<T> & refptr<T>::operator=(T * ptr)
|
|||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
m_ptr = ptr;
|
m_ptr = ptr;
|
||||||
m_refCount = new int;
|
m_refCount = new std::atomic<int>(1);
|
||||||
*m_refCount = 1;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +69,7 @@ template <typename T> void refptr<T>::cloneFrom(const refptr<T> & orig)
|
|||||||
this->m_ptr = orig.m_ptr;
|
this->m_ptr = orig.m_ptr;
|
||||||
this->m_refCount = orig.m_refCount;
|
this->m_refCount = orig.m_refCount;
|
||||||
if (m_refCount != NULL)
|
if (m_refCount != NULL)
|
||||||
(*m_refCount)++;
|
m_refCount->fetch_add(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> refptr<T>::~refptr()
|
template <typename T> refptr<T>::~refptr()
|
||||||
@@ -79,15 +81,13 @@ template <typename T> void refptr<T>::destroy()
|
|||||||
{
|
{
|
||||||
if (m_refCount != NULL)
|
if (m_refCount != NULL)
|
||||||
{
|
{
|
||||||
if (*m_refCount <= 1)
|
/* fetch_sub returns the value prior to the decrement; if it was 1
|
||||||
|
* then this was the last reference and we own the cleanup */
|
||||||
|
if (m_refCount->fetch_sub(1, std::memory_order_acq_rel) == 1)
|
||||||
{
|
{
|
||||||
delete m_ptr;
|
delete m_ptr;
|
||||||
delete m_refCount;
|
delete m_refCount;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
(*m_refCount)--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
/* Single translation unit that compiles the stb_image implementation. */
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user