gpuray_glsl

annotate 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
rev   line source
nuclear@0 1 #include <algorithm>
nuclear@0 2 #include <assert.h>
nuclear@0 3 #include "gpuscene.h"
nuclear@0 4 #include "sphere.h"
nuclear@0 5 #include "plane.h"
nuclear@0 6 #include "box.h"
nuclear@0 7 #include "opengl.h"
nuclear@0 8
nuclear@0 9 GPUScene::GPUScene()
nuclear@0 10 {
nuclear@0 11 glGenTextures(NUM_TEXTURES, textures);
nuclear@0 12
nuclear@0 13 for(int i=0; i<NUM_TEXTURES; i++) {
nuclear@0 14 glBindTexture(GL_TEXTURE_2D, textures[i]);
nuclear@0 15 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
nuclear@0 16 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
nuclear@0 17 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
nuclear@0 18 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
nuclear@0 19 }
nuclear@0 20
nuclear@0 21 xform_buf = 0;
nuclear@0 22 }
nuclear@0 23
nuclear@0 24 GPUScene::~GPUScene()
nuclear@0 25 {
nuclear@0 26 glDeleteTextures(NUM_TEXTURES, textures);
nuclear@0 27 delete [] xform_buf;
nuclear@0 28 }
nuclear@0 29
nuclear@0 30 bool GPUScene::create_textures()
nuclear@0 31 {
nuclear@0 32 // must be first to generate the megatecture rectangles
nuclear@0 33 create_megatexture();
nuclear@0 34
nuclear@0 35 Sphere *sph;
nuclear@0 36 Plane *plane;
nuclear@0 37 Box *box;
nuclear@0 38
nuclear@0 39 std::vector<Sphere*> spheres;
nuclear@0 40 std::vector<Plane*> planes;
nuclear@0 41 std::vector<Box*> boxes;
nuclear@0 42
nuclear@0 43 // collect all objects into the different type-specific arrays
nuclear@0 44 for(auto obj : objects) {
nuclear@0 45 if((sph = dynamic_cast<Sphere*>(obj))) {
nuclear@0 46 spheres.push_back(sph);
nuclear@0 47
nuclear@0 48 } else if((plane = dynamic_cast<Plane*>(obj))) {
nuclear@0 49 planes.push_back(plane);
nuclear@0 50
nuclear@0 51 } else if((box = dynamic_cast<Box*>(obj))) {
nuclear@0 52 boxes.push_back(box);
nuclear@0 53
nuclear@0 54 } else {
nuclear@0 55 fprintf(stderr, "skipping object of unknown type: %s\n", obj->get_name());
nuclear@0 56 }
nuclear@0 57 }
nuclear@0 58
nuclear@0 59 create_sphere_texture(spheres);
nuclear@0 60 create_plane_texture(planes);
nuclear@0 61 create_box_texture(boxes);
nuclear@0 62
nuclear@0 63 create_env_texture();
nuclear@0 64 create_xform_texture();
nuclear@0 65
nuclear@0 66 return true;
nuclear@0 67 }
nuclear@0 68
nuclear@0 69 unsigned int GPUScene::get_texture(int which) const
nuclear@0 70 {
nuclear@0 71 return textures[which];
nuclear@0 72 }
nuclear@0 73
nuclear@0 74 #define MAT_START 4
nuclear@0 75 static void copy_material(Vector4 *ptr, const Material *mtl)
nuclear@0 76 {
nuclear@0 77 ptr[MAT_START].x = mtl->diffuse.x;
nuclear@0 78 ptr[MAT_START].y = mtl->diffuse.y;
nuclear@0 79 ptr[MAT_START].z = mtl->diffuse.z;
nuclear@0 80 ptr[MAT_START].w = mtl->transparency;
nuclear@0 81
nuclear@0 82 ptr[MAT_START + 1].x = mtl->specular.x;
nuclear@0 83 ptr[MAT_START + 1].y = mtl->specular.y;
nuclear@0 84 ptr[MAT_START + 1].z = mtl->specular.z;
nuclear@0 85 ptr[MAT_START + 1].w = mtl->shininess;
nuclear@0 86
nuclear@0 87 ptr[MAT_START + 2].x = mtl->reflectivity;
nuclear@0 88 ptr[MAT_START + 2].y = mtl->ior;
nuclear@0 89
nuclear@0 90 ptr[MAT_START + 3] = mtl->mega_rect;
nuclear@0 91 }
nuclear@0 92
nuclear@0 93 int GPUScene::object_index(const Object *obj) const
nuclear@0 94 {
nuclear@0 95 for(int i=0; i<(int)objects.size(); i++) {
nuclear@0 96 if(objects[i] == obj) {
nuclear@0 97 return i;
nuclear@0 98 }
nuclear@0 99 }
nuclear@0 100 abort(); // can't happen
nuclear@0 101 return -1;
nuclear@0 102 }
nuclear@0 103
nuclear@0 104 #define OBJ_LINE_WIDTH 16
nuclear@0 105 void GPUScene::create_sphere_texture(const std::vector<Sphere*> &spheres)
nuclear@0 106 {
nuclear@0 107 int xsz = OBJ_LINE_WIDTH;
nuclear@0 108 int ysz = (int)spheres.size() + 1;
nuclear@0 109 int tex_ysz = next_pow2(ysz);
nuclear@0 110
nuclear@0 111 Vector4 *pixels = new Vector4[xsz * tex_ysz];
nuclear@0 112
nuclear@0 113 pixels[0].x = (float)ysz;
nuclear@0 114 pixels[0].y = (float)tex_ysz;
nuclear@0 115 pixels[0].z = 0.5;
nuclear@0 116 pixels[0].w = 1.0;
nuclear@0 117
nuclear@0 118 Vector4 *pixptr = pixels + xsz;
nuclear@0 119
nuclear@0 120 for(size_t i=0; i<spheres.size(); i++) {
nuclear@0 121 pixptr[0].x = object_index(spheres[i]);
nuclear@0 122
nuclear@0 123 pixptr[1].x = spheres[i]->pos.x;
nuclear@0 124 pixptr[1].y = spheres[i]->pos.y;
nuclear@0 125 pixptr[1].z = spheres[i]->pos.z;
nuclear@0 126 pixptr[1].w = spheres[i]->radius;
nuclear@0 127
nuclear@0 128 copy_material(pixptr, &spheres[i]->material);
nuclear@0 129 pixptr += OBJ_LINE_WIDTH;
nuclear@0 130 }
nuclear@0 131
nuclear@0 132 glBindTexture(GL_TEXTURE_2D, textures[TEX_SPHERE]);
nuclear@0 133 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
nuclear@0 134
nuclear@0 135 delete [] pixels;
nuclear@0 136 }
nuclear@0 137
nuclear@0 138 void GPUScene::create_plane_texture(const std::vector<Plane*> &planes)
nuclear@0 139 {
nuclear@0 140 int xsz = OBJ_LINE_WIDTH;
nuclear@0 141 int ysz = (int)planes.size() + 1;
nuclear@0 142 int tex_ysz = next_pow2(ysz);
nuclear@0 143
nuclear@0 144 Vector4 *pixels = new Vector4[xsz * tex_ysz];
nuclear@0 145
nuclear@0 146 pixels[0].x = (float)ysz;
nuclear@0 147 pixels[0].y = (float)tex_ysz;
nuclear@0 148
nuclear@0 149 Vector4 *pixptr = pixels + xsz;
nuclear@0 150
nuclear@0 151 for(size_t i=0; i<planes.size(); i++) {
nuclear@0 152 pixptr[0].x = object_index(planes[i]);
nuclear@0 153
nuclear@0 154 pixptr[1].x = planes[i]->normal.x;
nuclear@0 155 pixptr[1].y = planes[i]->normal.y;
nuclear@0 156 pixptr[1].z = planes[i]->normal.z;
nuclear@0 157 pixptr[1].w = planes[i]->dist;
nuclear@0 158
nuclear@0 159 copy_material(pixptr, &planes[i]->material);
nuclear@0 160 pixptr += OBJ_LINE_WIDTH;
nuclear@0 161 }
nuclear@0 162
nuclear@0 163 glBindTexture(GL_TEXTURE_2D, textures[TEX_PLANE]);
nuclear@0 164 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
nuclear@0 165
nuclear@0 166 delete [] pixels;
nuclear@0 167 }
nuclear@0 168
nuclear@0 169 void GPUScene::create_box_texture(const std::vector<Box*> &boxes)
nuclear@0 170 {
nuclear@0 171 int xsz = OBJ_LINE_WIDTH;
nuclear@0 172 int ysz = (int)boxes.size() + 1;
nuclear@0 173 int tex_ysz = next_pow2(ysz);
nuclear@0 174
nuclear@0 175 Vector4 *pixels = new Vector4[xsz * tex_ysz];
nuclear@0 176
nuclear@0 177 pixels[0].x = (float)ysz;
nuclear@0 178 pixels[0].y = (float)tex_ysz;
nuclear@0 179
nuclear@0 180 Vector4 *pixptr = pixels + xsz;
nuclear@0 181
nuclear@0 182 for(size_t i=0; i<boxes.size(); i++) {
nuclear@0 183 pixptr[0].x = object_index(boxes[i]);
nuclear@0 184 pixptr[1] = boxes[i]->min;
nuclear@0 185 pixptr[2] = boxes[i]->max;
nuclear@0 186
nuclear@0 187 copy_material(pixptr, &boxes[i]->material);
nuclear@0 188 pixptr += OBJ_LINE_WIDTH;
nuclear@0 189 }
nuclear@0 190
nuclear@0 191 glBindTexture(GL_TEXTURE_2D, textures[TEX_BOX]);
nuclear@0 192 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
nuclear@0 193
nuclear@0 194 delete [] pixels;
nuclear@0 195 }
nuclear@0 196
nuclear@0 197 void GPUScene::create_megatexture()
nuclear@0 198 {
nuclear@0 199 // at least a 1x1 dummy white texture
nuclear@0 200 int xsz = 1;
nuclear@0 201 int ysz = 1;
nuclear@0 202 int num_textures = 0;
nuclear@0 203
nuclear@0 204 for(auto obj : objects) {
nuclear@0 205 // only need 2D textures at this point
nuclear@0 206 Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex);
nuclear@0 207 if(tex) {
nuclear@0 208 const Image *img = tex->get_image();
nuclear@0 209
nuclear@0 210 xsz = std::max(xsz, img->xsz);
nuclear@0 211 ysz += img->ysz;
nuclear@0 212 num_textures++;
nuclear@0 213 }
nuclear@0 214 }
nuclear@0 215
nuclear@0 216 int tex_xsz = next_pow2(xsz);
nuclear@0 217 int tex_ysz = next_pow2(ysz);
nuclear@0 218
nuclear@0 219 Color *pixels = new Color[tex_xsz * tex_ysz];
nuclear@0 220
nuclear@0 221 // null texture
nuclear@0 222 pixels[0] = Color(1, 1, 1);
nuclear@0 223
nuclear@0 224 Color *pixptr = pixels + tex_xsz;
nuclear@0 225
nuclear@0 226 float offs_y = 0.0;
nuclear@0 227 for(auto obj : objects) {
nuclear@0 228 Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex);
nuclear@0 229 if(tex) {
nuclear@0 230 const Image *img = tex->get_image();
nuclear@0 231
nuclear@0 232 Vector4 rect{0.0, offs_y, (float)img->xsz / (float)tex_xsz,
nuclear@0 233 (float)img->ysz / (float)tex_ysz};
nuclear@0 234
nuclear@0 235 offs_y += rect.w;
nuclear@0 236
nuclear@0 237 obj->material.mega_rect = rect;
nuclear@0 238
nuclear@0 239 for(int i=0; i<img->ysz; i++) {
nuclear@0 240 memcpy(pixptr, img->pixels + i * img->xsz, img->xsz * sizeof *pixels);
nuclear@0 241 pixptr += tex_xsz;
nuclear@0 242 }
nuclear@0 243 } else {
nuclear@0 244 obj->material.mega_rect = Vector4(0, 0, 0, 0);
nuclear@0 245 }
nuclear@0 246 }
nuclear@0 247
nuclear@0 248 glBindTexture(GL_TEXTURE_2D, textures[TEX_TEXTURE]);
nuclear@0 249 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, pixels);
nuclear@0 250
nuclear@0 251 delete [] pixels;
nuclear@0 252 }
nuclear@0 253
nuclear@0 254 void GPUScene::create_env_texture()
nuclear@0 255 {
nuclear@0 256 // create the scene cubemap, or a null cubemap if we don't have one
nuclear@0 257 glDeleteTextures(1, textures + TEX_ENV); // cause it's not a 2D texture :)
nuclear@0 258
nuclear@0 259 glGenTextures(1, textures + TEX_ENV);
nuclear@0 260 glBindTexture(GL_TEXTURE_CUBE_MAP, textures[TEX_ENV]);
nuclear@0 261 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@0 262 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@0 263 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
nuclear@0 264 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
nuclear@0 265 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
nuclear@0 266
nuclear@0 267 if(envmap) {
nuclear@0 268 // we have an environment cubemap, just pass the data to OpenGL
nuclear@0 269 for(int i=0; i<6; i++) {
nuclear@0 270 const Image *img = envmap->get_image(i);
nuclear@0 271
nuclear@0 272 int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
nuclear@0 273 glTexImage2D(face, 0, GL_RGB16F, img->xsz, img->ysz, 0, GL_RGB, GL_FLOAT, img->pixels);
nuclear@0 274 }
nuclear@0 275 } else {
nuclear@0 276 // we don't have an env cubemap, make a dummy 1x1 cubemap with the background color
nuclear@0 277 for(int i=0; i<6; i++) {
nuclear@0 278 int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
nuclear@0 279 glTexImage2D(face, 0, GL_RGB16F, 1, 1, 0, GL_RGB, GL_FLOAT, &bgcolor);
nuclear@0 280 }
nuclear@0 281 }
nuclear@0 282 }
nuclear@0 283
nuclear@0 284 #define XFORM_LINE_WIDTH OBJ_LINE_WIDTH
nuclear@0 285 void GPUScene::create_xform_texture()
nuclear@0 286 {
nuclear@0 287 int tex_xsz = XFORM_LINE_WIDTH;
nuclear@0 288 int tex_ysz = next_pow2((int)objects.size() + 1); // leave space for the descriptor
nuclear@0 289
nuclear@0 290 glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]);
nuclear@0 291 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
nuclear@0 292
nuclear@0 293 update_xform_texture();
nuclear@0 294 }
nuclear@0 295
nuclear@0 296 void GPUScene::update_xform_texture()
nuclear@0 297 {
nuclear@0 298 int tex_xsz = XFORM_LINE_WIDTH;
nuclear@0 299 int tex_ysz = next_pow2((int)objects.size() + 1); // leave space for the descriptor
nuclear@0 300
nuclear@0 301 if(!xform_buf) {
nuclear@0 302 xform_buf = new Vector4[tex_xsz * tex_ysz];
nuclear@0 303 xform_buf[0].x = tex_ysz; // descriptor
nuclear@0 304 }
nuclear@0 305
nuclear@0 306 Vector4 *pixptr = xform_buf + tex_xsz;
nuclear@0 307 for(auto obj : objects) {
nuclear@0 308 for(int i=0; i<4; i++) {
nuclear@0 309 pixptr[i] = obj->xform.get_column_vector(i);
nuclear@0 310 pixptr[i + 4] = obj->inv_xform.get_column_vector(i);
nuclear@0 311 }
nuclear@0 312 pixptr += tex_xsz;
nuclear@0 313 }
nuclear@0 314
nuclear@0 315 glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]);
nuclear@0 316 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_xsz, tex_ysz, GL_RGBA, GL_FLOAT, xform_buf);
nuclear@0 317 }