gpuray_glsl

diff src/gpuscene.cc @ 0:f234630e38ff

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 09 Nov 2014 13:03:36 +0200
parents
children 2ed3da7dc0bc
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/gpuscene.cc	Sun Nov 09 13:03:36 2014 +0200
     1.3 @@ -0,0 +1,317 @@
     1.4 +#include <algorithm>
     1.5 +#include <assert.h>
     1.6 +#include "gpuscene.h"
     1.7 +#include "sphere.h"
     1.8 +#include "plane.h"
     1.9 +#include "box.h"
    1.10 +#include "opengl.h"
    1.11 +
    1.12 +GPUScene::GPUScene()
    1.13 +{
    1.14 +	glGenTextures(NUM_TEXTURES, textures);
    1.15 +
    1.16 +	for(int i=0; i<NUM_TEXTURES; i++) {
    1.17 +		glBindTexture(GL_TEXTURE_2D, textures[i]);
    1.18 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    1.19 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    1.20 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    1.21 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    1.22 +	}
    1.23 +
    1.24 +	xform_buf = 0;
    1.25 +}
    1.26 +
    1.27 +GPUScene::~GPUScene()
    1.28 +{
    1.29 +	glDeleteTextures(NUM_TEXTURES, textures);
    1.30 +	delete [] xform_buf;
    1.31 +}
    1.32 +
    1.33 +bool GPUScene::create_textures()
    1.34 +{
    1.35 +	// must be first to generate the megatecture rectangles
    1.36 +	create_megatexture();
    1.37 +
    1.38 +	Sphere *sph;
    1.39 +	Plane *plane;
    1.40 +	Box *box;
    1.41 +
    1.42 +	std::vector<Sphere*> spheres;
    1.43 +	std::vector<Plane*> planes;
    1.44 +	std::vector<Box*> boxes;
    1.45 +
    1.46 +	// collect all objects into the different type-specific arrays
    1.47 +	for(auto obj : objects) {
    1.48 +		if((sph = dynamic_cast<Sphere*>(obj))) {
    1.49 +			spheres.push_back(sph);
    1.50 +
    1.51 +		} else if((plane = dynamic_cast<Plane*>(obj))) {
    1.52 +			planes.push_back(plane);
    1.53 +
    1.54 +		} else if((box = dynamic_cast<Box*>(obj))) {
    1.55 +			boxes.push_back(box);
    1.56 +
    1.57 +		} else {
    1.58 +			fprintf(stderr, "skipping object of unknown type: %s\n", obj->get_name());
    1.59 +		}
    1.60 +	}
    1.61 +
    1.62 +	create_sphere_texture(spheres);
    1.63 +	create_plane_texture(planes);
    1.64 +	create_box_texture(boxes);
    1.65 +
    1.66 +	create_env_texture();
    1.67 +	create_xform_texture();
    1.68 +
    1.69 +	return true;
    1.70 +}
    1.71 +
    1.72 +unsigned int GPUScene::get_texture(int which) const
    1.73 +{
    1.74 +	return textures[which];
    1.75 +}
    1.76 +
    1.77 +#define MAT_START	4
    1.78 +static void copy_material(Vector4 *ptr, const Material *mtl)
    1.79 +{
    1.80 +	ptr[MAT_START].x = mtl->diffuse.x;
    1.81 +	ptr[MAT_START].y = mtl->diffuse.y;
    1.82 +	ptr[MAT_START].z = mtl->diffuse.z;
    1.83 +	ptr[MAT_START].w = mtl->transparency;
    1.84 +
    1.85 +	ptr[MAT_START + 1].x = mtl->specular.x;
    1.86 +	ptr[MAT_START + 1].y = mtl->specular.y;
    1.87 +	ptr[MAT_START + 1].z = mtl->specular.z;
    1.88 +	ptr[MAT_START + 1].w = mtl->shininess;
    1.89 +
    1.90 +	ptr[MAT_START + 2].x = mtl->reflectivity;
    1.91 +	ptr[MAT_START + 2].y = mtl->ior;
    1.92 +
    1.93 +	ptr[MAT_START + 3] = mtl->mega_rect;
    1.94 +}
    1.95 +
    1.96 +int GPUScene::object_index(const Object *obj) const
    1.97 +{
    1.98 +	for(int i=0; i<(int)objects.size(); i++) {
    1.99 +		if(objects[i] == obj) {
   1.100 +			return i;
   1.101 +		}
   1.102 +	}
   1.103 +	abort();	// can't happen
   1.104 +	return -1;
   1.105 +}
   1.106 +
   1.107 +#define OBJ_LINE_WIDTH	16
   1.108 +void GPUScene::create_sphere_texture(const std::vector<Sphere*> &spheres)
   1.109 +{
   1.110 +	int xsz = OBJ_LINE_WIDTH;
   1.111 +	int ysz = (int)spheres.size() + 1;
   1.112 +	int tex_ysz = next_pow2(ysz);
   1.113 +
   1.114 +	Vector4 *pixels = new Vector4[xsz * tex_ysz];
   1.115 +
   1.116 +	pixels[0].x = (float)ysz;
   1.117 +	pixels[0].y = (float)tex_ysz;
   1.118 +	pixels[0].z = 0.5;
   1.119 +	pixels[0].w = 1.0;
   1.120 +
   1.121 +	Vector4 *pixptr = pixels + xsz;
   1.122 +
   1.123 +	for(size_t i=0; i<spheres.size(); i++) {
   1.124 +		pixptr[0].x = object_index(spheres[i]);
   1.125 +
   1.126 +		pixptr[1].x = spheres[i]->pos.x;
   1.127 +		pixptr[1].y = spheres[i]->pos.y;
   1.128 +		pixptr[1].z = spheres[i]->pos.z;
   1.129 +		pixptr[1].w = spheres[i]->radius;
   1.130 +
   1.131 +		copy_material(pixptr, &spheres[i]->material);
   1.132 +		pixptr += OBJ_LINE_WIDTH;
   1.133 +	}
   1.134 +
   1.135 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_SPHERE]);
   1.136 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
   1.137 +
   1.138 +	delete [] pixels;
   1.139 +}
   1.140 +
   1.141 +void GPUScene::create_plane_texture(const std::vector<Plane*> &planes)
   1.142 +{
   1.143 +	int xsz = OBJ_LINE_WIDTH;
   1.144 +	int ysz = (int)planes.size() + 1;
   1.145 +	int tex_ysz = next_pow2(ysz);
   1.146 +
   1.147 +	Vector4 *pixels = new Vector4[xsz * tex_ysz];
   1.148 +
   1.149 +	pixels[0].x = (float)ysz;
   1.150 +	pixels[0].y = (float)tex_ysz;
   1.151 +
   1.152 +	Vector4 *pixptr = pixels + xsz;
   1.153 +
   1.154 +	for(size_t i=0; i<planes.size(); i++) {
   1.155 +		pixptr[0].x = object_index(planes[i]);
   1.156 +
   1.157 +		pixptr[1].x = planes[i]->normal.x;
   1.158 +		pixptr[1].y = planes[i]->normal.y;
   1.159 +		pixptr[1].z = planes[i]->normal.z;
   1.160 +		pixptr[1].w = planes[i]->dist;
   1.161 +
   1.162 +		copy_material(pixptr, &planes[i]->material);
   1.163 +		pixptr += OBJ_LINE_WIDTH;
   1.164 +	}
   1.165 +
   1.166 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_PLANE]);
   1.167 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
   1.168 +
   1.169 +	delete [] pixels;
   1.170 +}
   1.171 +
   1.172 +void GPUScene::create_box_texture(const std::vector<Box*> &boxes)
   1.173 +{
   1.174 +	int xsz = OBJ_LINE_WIDTH;
   1.175 +	int ysz = (int)boxes.size() + 1;
   1.176 +	int tex_ysz = next_pow2(ysz);
   1.177 +
   1.178 +	Vector4 *pixels = new Vector4[xsz * tex_ysz];
   1.179 +
   1.180 +	pixels[0].x = (float)ysz;
   1.181 +	pixels[0].y = (float)tex_ysz;
   1.182 +
   1.183 +	Vector4 *pixptr = pixels + xsz;
   1.184 +
   1.185 +	for(size_t i=0; i<boxes.size(); i++) {
   1.186 +		pixptr[0].x = object_index(boxes[i]);
   1.187 +		pixptr[1] = boxes[i]->min;
   1.188 +		pixptr[2] = boxes[i]->max;
   1.189 +
   1.190 +		copy_material(pixptr, &boxes[i]->material);
   1.191 +		pixptr += OBJ_LINE_WIDTH;
   1.192 +	}
   1.193 +
   1.194 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_BOX]);
   1.195 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
   1.196 +
   1.197 +	delete [] pixels;
   1.198 +}
   1.199 +
   1.200 +void GPUScene::create_megatexture()
   1.201 +{
   1.202 +	// at least a 1x1 dummy white texture
   1.203 +	int xsz = 1;
   1.204 +	int ysz = 1;
   1.205 +	int num_textures = 0;
   1.206 +
   1.207 +	for(auto obj : objects) {
   1.208 +		// only need 2D textures at this point
   1.209 +		Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex);
   1.210 +		if(tex) {
   1.211 +			const Image *img = tex->get_image();
   1.212 +
   1.213 +			xsz = std::max(xsz, img->xsz);
   1.214 +			ysz += img->ysz;
   1.215 +			num_textures++;
   1.216 +		}
   1.217 +	}
   1.218 +
   1.219 +	int tex_xsz = next_pow2(xsz);
   1.220 +	int tex_ysz = next_pow2(ysz);
   1.221 +
   1.222 +	Color *pixels = new Color[tex_xsz * tex_ysz];
   1.223 +
   1.224 +	// null texture
   1.225 +	pixels[0] = Color(1, 1, 1);
   1.226 +
   1.227 +	Color *pixptr = pixels + tex_xsz;
   1.228 +
   1.229 +	float offs_y = 0.0;
   1.230 +	for(auto obj : objects) {
   1.231 +		Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex);
   1.232 +		if(tex) {
   1.233 +			const Image *img = tex->get_image();
   1.234 +
   1.235 +			Vector4 rect{0.0, offs_y, (float)img->xsz / (float)tex_xsz,
   1.236 +				(float)img->ysz / (float)tex_ysz};
   1.237 +
   1.238 +			offs_y += rect.w;
   1.239 +
   1.240 +			obj->material.mega_rect = rect;
   1.241 +
   1.242 +			for(int i=0; i<img->ysz; i++) {
   1.243 +				memcpy(pixptr, img->pixels + i * img->xsz, img->xsz * sizeof *pixels);
   1.244 +				pixptr += tex_xsz;
   1.245 +			}
   1.246 +		} else {
   1.247 +			obj->material.mega_rect = Vector4(0, 0, 0, 0);
   1.248 +		}
   1.249 +	}
   1.250 +
   1.251 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_TEXTURE]);
   1.252 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, pixels);
   1.253 +
   1.254 +	delete [] pixels;
   1.255 +}
   1.256 +
   1.257 +void GPUScene::create_env_texture()
   1.258 +{
   1.259 +	// create the scene cubemap, or a null cubemap if we don't have one
   1.260 +	glDeleteTextures(1, textures + TEX_ENV);	// cause it's not a 2D texture :)
   1.261 +
   1.262 +	glGenTextures(1, textures + TEX_ENV);
   1.263 +	glBindTexture(GL_TEXTURE_CUBE_MAP, textures[TEX_ENV]);
   1.264 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   1.265 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1.266 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   1.267 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   1.268 +	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
   1.269 +
   1.270 +	if(envmap) {
   1.271 +		// we have an environment cubemap, just pass the data to OpenGL
   1.272 +		for(int i=0; i<6; i++) {
   1.273 +			const Image *img = envmap->get_image(i);
   1.274 +
   1.275 +			int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
   1.276 +			glTexImage2D(face, 0, GL_RGB16F, img->xsz, img->ysz, 0, GL_RGB, GL_FLOAT, img->pixels);
   1.277 +		}
   1.278 +	} else {
   1.279 +		// we don't have an env cubemap, make a dummy 1x1 cubemap with the background color
   1.280 +		for(int i=0; i<6; i++) {
   1.281 +			int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
   1.282 +			glTexImage2D(face, 0, GL_RGB16F, 1, 1, 0, GL_RGB, GL_FLOAT, &bgcolor);
   1.283 +		}
   1.284 +	}
   1.285 +}
   1.286 +
   1.287 +#define XFORM_LINE_WIDTH	OBJ_LINE_WIDTH
   1.288 +void GPUScene::create_xform_texture()
   1.289 +{
   1.290 +	int tex_xsz = XFORM_LINE_WIDTH;
   1.291 +	int tex_ysz = next_pow2((int)objects.size() + 1);	// leave space for the descriptor
   1.292 +
   1.293 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]);
   1.294 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
   1.295 +
   1.296 +	update_xform_texture();
   1.297 +}
   1.298 +
   1.299 +void GPUScene::update_xform_texture()
   1.300 +{
   1.301 +	int tex_xsz = XFORM_LINE_WIDTH;
   1.302 +	int tex_ysz = next_pow2((int)objects.size() + 1);	// leave space for the descriptor
   1.303 +
   1.304 +	if(!xform_buf) {
   1.305 +		xform_buf = new Vector4[tex_xsz * tex_ysz];
   1.306 +		xform_buf[0].x = tex_ysz;	// descriptor
   1.307 +	}
   1.308 +
   1.309 +	Vector4 *pixptr = xform_buf + tex_xsz;
   1.310 +	for(auto obj : objects) {
   1.311 +		for(int i=0; i<4; i++) {
   1.312 +			pixptr[i] = obj->xform.get_column_vector(i);
   1.313 +			pixptr[i + 4] = obj->inv_xform.get_column_vector(i);
   1.314 +		}
   1.315 +		pixptr += tex_xsz;
   1.316 +	}
   1.317 +
   1.318 +	glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]);
   1.319 +	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_xsz, tex_ysz, GL_RGBA, GL_FLOAT, xform_buf);
   1.320 +}