goat3dgfx

diff src/vr/vr.cc @ 11:d061fe1a31ec

compile vr source files or not
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 24 Nov 2013 14:00:14 +0200
parents
children 7d6b667821cf
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/vr/vr.cc	Sun Nov 24 14:00:14 2013 +0200
     1.3 @@ -0,0 +1,384 @@
     1.4 +#include <stdio.h>
     1.5 +#include <GL/glew.h>
     1.6 +#include "vr.h"
     1.7 +#include "vr_impl.h"
     1.8 +#include "vr_sdr.h"
     1.9 +
    1.10 +#ifndef WIN32
    1.11 +#include <alloca.h>
    1.12 +#else
    1.13 +#include <malloc.h>
    1.14 +#endif
    1.15 +
    1.16 +static void init_ctx();
    1.17 +static bool init_ovr();
    1.18 +static bool init_sdr();
    1.19 +
    1.20 +VRContext vr_ctx;
    1.21 +static unsigned int sdrprog;
    1.22 +
    1.23 +extern "C" int vr_init(enum vr_init_mode mode)
    1.24 +{
    1.25 +	init_ctx();
    1.26 +
    1.27 +	if(!init_ovr()) {
    1.28 +		return -1;
    1.29 +	}
    1.30 +
    1.31 +	if(!init_sdr()) {
    1.32 +		return -1;
    1.33 +	}
    1.34 +
    1.35 +	return 0;
    1.36 +}
    1.37 +
    1.38 +extern "C" void vr_shutdown(void)
    1.39 +{
    1.40 +	delete [] vr_ctx.info.display;
    1.41 +	//System::Destroy();
    1.42 +}
    1.43 +
    1.44 +static void init_ctx()
    1.45 +{
    1.46 +	vr_ctx.info.width = 1280;
    1.47 +	vr_ctx.info.height = 800;
    1.48 +	vr_ctx.info.fov = M_PI / 2.0;
    1.49 +	vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height;
    1.50 +	vr_ctx.info.ipd = 0.035;
    1.51 +	vr_ctx.info.scale = 1.0;
    1.52 +}
    1.53 +
    1.54 +static bool init_ovr()
    1.55 +{
    1.56 +	LogMaskConstants log_level = LogMask_All;
    1.57 +	// initialize Oculus SDK
    1.58 +	const char *logenv = getenv("VR_LOGLEVEL");
    1.59 +	if(logenv) {
    1.60 +		switch(atoi(logenv)) {
    1.61 +		case 0:
    1.62 +			log_level = LogMask_None;
    1.63 +			break;
    1.64 +		case 1:
    1.65 +			log_level = LogMask_Regular;
    1.66 +			break;
    1.67 +		case 2:
    1.68 +		default:
    1.69 +			log_level = LogMask_All;
    1.70 +			break;
    1.71 +		}
    1.72 +	}
    1.73 +
    1.74 +	System::Init(Log::ConfigureDefaultLog(log_level));
    1.75 +	if(!(vr_ctx.ovr_devman = DeviceManager::Create())) {
    1.76 +		fprintf(stderr, "failed to create OVR device manager\n");
    1.77 +		return false;
    1.78 +	}
    1.79 +
    1.80 +	// create the display device
    1.81 +	HMDInfo info;
    1.82 +	if(!(vr_ctx.ovr_hmd_dev = vr_ctx.ovr_devman->EnumerateDevices<HMDDevice>().CreateDevice())) {
    1.83 +		fprintf(stderr, "no oculus rift devices found\n");
    1.84 +	} else {
    1.85 +		if(vr_ctx.ovr_hmd_dev->GetDeviceInfo(&info)) {
    1.86 +			printf("oculus device info:\n");
    1.87 +			printf("  name: %s\n", info.DisplayDeviceName);
    1.88 +			printf("  ipd: %f\n", info.InterpupillaryDistance);
    1.89 +			printf("  distortion: %f %f %f %f\n", info.DistortionK[0],
    1.90 +					info.DistortionK[1], info.DistortionK[2], info.DistortionK[3]);
    1.91 +		}
    1.92 +
    1.93 +		// calculate and store viewing parameters
    1.94 +		vr_ctx.info.width = info.HResolution;
    1.95 +		vr_ctx.info.height = info.VResolution;
    1.96 +		vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height;
    1.97 +
    1.98 +		vr_ctx.info.ipd = info.InterpupillaryDistance;
    1.99 +		for(int i=0; i<4; i++) {
   1.100 +			vr_ctx.info.distort[i] = info.DistortionK[i];
   1.101 +		}
   1.102 +
   1.103 +		Util::Render::StereoConfig stereohelp;
   1.104 +		stereohelp.SetFullViewport(Util::Render::Viewport(0, 0, vr_ctx.info.width, vr_ctx.info.height));
   1.105 +		stereohelp.SetStereoMode(Util::Render::Stereo_LeftRight_Multipass);
   1.106 +		stereohelp.SetHMDInfo(info);
   1.107 +		stereohelp.SetDistortionFitPointVP(-1.0, 0.0);
   1.108 +
   1.109 +		vr_ctx.info.scale = stereohelp.GetDistortionScale();
   1.110 +
   1.111 +		float vhalfsz = vr_ctx.info.scale * info.VScreenSize * 0.5;
   1.112 +		vr_ctx.info.fov = 2.0 * atan(vhalfsz / info.EyeToScreenDistance);
   1.113 +
   1.114 +		vr_ctx.info.lens_center_offset = 0.5 - info.LensSeparationDistance / info.HScreenSize;
   1.115 +
   1.116 +		// calculate center of projection shift to match the lens positions
   1.117 +		float center_dist_meters = info.HScreenSize * 0.25;
   1.118 +		float proj_shift = center_dist_meters - info.LensSeparationDistance * 0.5;
   1.119 +		vr_ctx.info.proj_center_offset = 4.0 * proj_shift / info.HScreenSize;
   1.120 +
   1.121 +		// grab the display info
   1.122 +		vr_ctx.info.display = new char[strlen(info.DisplayDeviceName) + 1];
   1.123 +		strcpy(vr_ctx.info.display, info.DisplayDeviceName);
   1.124 +
   1.125 +		vr_ctx.info.display_xoffs = info.DesktopX;
   1.126 +		vr_ctx.info.display_yoffs = info.DesktopY;
   1.127 +
   1.128 +		printf("display: \"%s\" offset: %+d %+d\n", vr_ctx.info.display,
   1.129 +				vr_ctx.info.display_xoffs, vr_ctx.info.display_yoffs);
   1.130 +	}
   1.131 +
   1.132 +	// get the sensor device
   1.133 +	if(vr_ctx.ovr_hmd_dev) {
   1.134 +		if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_hmd_dev->GetSensor())) {
   1.135 +			fprintf(stderr, "failed to get oculus sensor device\n");
   1.136 +		}
   1.137 +	} else {
   1.138 +		if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_devman->EnumerateDevices<SensorDevice>().CreateDevice())) {
   1.139 +			fprintf(stderr, "failed to get oculus sensor device\n");
   1.140 +		}
   1.141 +	}
   1.142 +
   1.143 +	if(vr_ctx.ovr_sensor_dev) {
   1.144 +		SensorInfo sinfo;
   1.145 +		if(vr_ctx.ovr_sensor_dev->GetDeviceInfo(&sinfo)) {
   1.146 +			printf("oculus sensor device info:\n");
   1.147 +			printf("  name: %s\n", sinfo.ProductName);
   1.148 +		}
   1.149 +
   1.150 +		vr_ctx.ovr_sfusion.AttachToSensor(vr_ctx.ovr_sensor_dev);
   1.151 +	}
   1.152 +	return true;
   1.153 +}
   1.154 +
   1.155 +#undef EXTERNAL_SHADER
   1.156 +
   1.157 +static bool init_sdr()
   1.158 +{
   1.159 +	int status;
   1.160 +
   1.161 +#ifdef EXTERNAL_SHADER
   1.162 +	FILE *fp = fopen("sdr/sdr.glsl", "rb");
   1.163 +	if(!fp) {
   1.164 +		perror("failed to load sdr.glsl");
   1.165 +		return false;
   1.166 +	}
   1.167 +	fseek(fp, 0, SEEK_END);
   1.168 +	long sz = ftell(fp);
   1.169 +	rewind(fp);
   1.170 +
   1.171 +	char *buf = (char*)alloca(sz + 1);
   1.172 +	fread(buf, 1, sz, fp);
   1.173 +	buf[sz] = 0;
   1.174 +	sdr_src = buf;
   1.175 +
   1.176 +	fclose(fp);
   1.177 +#endif
   1.178 +
   1.179 +	unsigned int sdr = glCreateShader(GL_FRAGMENT_SHADER);
   1.180 +	glShaderSource(sdr, 1, &sdr_src, 0);
   1.181 +	glCompileShader(sdr);
   1.182 +	glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
   1.183 +	if(!status) {
   1.184 +		fprintf(stderr, "failed to compile distortion shader\n");
   1.185 +
   1.186 +		int loglen;
   1.187 +		glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
   1.188 +
   1.189 +		if(loglen > 0) {
   1.190 +			char *log = (char*)alloca(loglen);
   1.191 +			glGetShaderInfoLog(sdr, loglen, &loglen, log);
   1.192 +			fprintf(stderr, "%s\n", log);
   1.193 +		}
   1.194 +
   1.195 +		return false;
   1.196 +	}
   1.197 +
   1.198 +	sdrprog = glCreateProgram();
   1.199 +	glAttachShader(sdrprog, sdr);
   1.200 +	glLinkProgram(sdrprog);
   1.201 +	if(!status) {
   1.202 +		fprintf(stderr, "failed to link distortion shader program\n");
   1.203 +		glDeleteShader(sdr);
   1.204 +		return false;
   1.205 +	}
   1.206 +
   1.207 +	int loc;
   1.208 +
   1.209 +	glUseProgram(sdrprog);
   1.210 +
   1.211 +	if((loc = glGetUniformLocation(sdrprog, "tex")) != -1) {
   1.212 +		glUniform1i(loc, 0);
   1.213 +	}
   1.214 +	if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) {
   1.215 +		glUniform1f(loc, 0);
   1.216 +	}
   1.217 +	if((loc = glGetUniformLocation(sdrprog, "scr_center")) != -1) {
   1.218 +		glUniform2f(loc, 0, 0);
   1.219 +	}
   1.220 +	if((loc = glGetUniformLocation(sdrprog, "scale")) != -1) {
   1.221 +		glUniform1f(loc, vr_ctx.info.scale);
   1.222 +	}
   1.223 +	if((loc = glGetUniformLocation(sdrprog, "aspect")) != -1) {
   1.224 +		printf("setting aspect: %f\n", vr_ctx.info.aspect / 2.0);
   1.225 +		glUniform1f(loc, vr_ctx.info.aspect / 2.0);
   1.226 +	}
   1.227 +	if((loc = glGetUniformLocation(sdrprog, "scale_in")) != -1) {
   1.228 +		glUniform2f(loc, 1, 1);
   1.229 +	}
   1.230 +	if((loc = glGetUniformLocation(sdrprog, "dist_factors")) != -1) {
   1.231 +		glUniform4f(loc, vr_ctx.info.distort[0], vr_ctx.info.distort[1],
   1.232 +				vr_ctx.info.distort[2], vr_ctx.info.distort[3]);
   1.233 +	}
   1.234 +
   1.235 +	return true;
   1.236 +}
   1.237 +
   1.238 +extern "C" const char *vr_get_display_name(void)
   1.239 +{
   1.240 +	return vr_ctx.info.display;
   1.241 +}
   1.242 +
   1.243 +extern "C" void vr_get_display_pos(int *xptr, int *yptr)
   1.244 +{
   1.245 +	*xptr = vr_ctx.info.display_xoffs;
   1.246 +	*yptr = vr_ctx.info.display_yoffs;
   1.247 +}
   1.248 +
   1.249 +extern "C" int vr_get_width(void)
   1.250 +{
   1.251 +	return vr_ctx.info.width;
   1.252 +}
   1.253 +
   1.254 +extern "C" int vr_get_height(void)
   1.255 +{
   1.256 +	return vr_ctx.info.height;
   1.257 +}
   1.258 +
   1.259 +extern "C" float vr_get_fov(void)
   1.260 +{
   1.261 +	return vr_ctx.info.fov;
   1.262 +}
   1.263 +
   1.264 +extern "C" float vr_get_aspect(void)
   1.265 +{
   1.266 +	return vr_ctx.info.aspect;
   1.267 +}
   1.268 +
   1.269 +extern "C" void vr_set_eyedist(float ipd)
   1.270 +{
   1.271 +	vr_ctx.info.ipd = ipd;
   1.272 +}
   1.273 +
   1.274 +extern "C" float vr_get_eyedist(void)
   1.275 +{
   1.276 +	return vr_ctx.info.ipd;
   1.277 +}
   1.278 +
   1.279 +extern "C" void vr_set_distort(const float *coef)
   1.280 +{
   1.281 +	memcpy(vr_ctx.info.distort, coef, sizeof vr_ctx.info.distort);
   1.282 +}
   1.283 +
   1.284 +extern "C" void vr_get_distort(float *coef)
   1.285 +{
   1.286 +	memcpy(coef, vr_ctx.info.distort, sizeof vr_ctx.info.distort);
   1.287 +}
   1.288 +
   1.289 +extern "C" void vr_set_prediction_sec(float dt)
   1.290 +{
   1.291 +	vr_ctx.ovr_sfusion.SetPrediction(dt);
   1.292 +}
   1.293 +
   1.294 +extern "C" float vr_get_prediction_sec(void)
   1.295 +{
   1.296 +	return vr_ctx.ovr_sfusion.GetPredictionDelta();
   1.297 +}
   1.298 +
   1.299 +extern "C" void vr_get_view_matrix(float *res, int eye)
   1.300 +{
   1.301 +	// TODO
   1.302 +}
   1.303 +
   1.304 +extern "C" void vr_get_proj_matrix(float *res, int eye)
   1.305 +{
   1.306 +	static float eye_scale[] = {0.0, 1.0, -1.0};
   1.307 +
   1.308 +	Matrix4f proj = Matrix4f::PerspectiveRH(vr_ctx.info.fov, vr_ctx.info.aspect / 2.0, 0.3, 1000.0);
   1.309 +	proj = Matrix4f::Translation(vr_ctx.info.proj_center_offset * eye_scale[eye], 0, 0) * proj;
   1.310 +
   1.311 +	memcpy(res, proj.M[0], 16 * sizeof(float));
   1.312 +}
   1.313 +
   1.314 +extern "C" void vr_get_translation(float *offs)
   1.315 +{
   1.316 +	// current oculus devkit doesn't do translation
   1.317 +	offs[0] = offs[1] = offs[2] = 0.0f;
   1.318 +}
   1.319 +
   1.320 +extern "C" void vr_get_rotation(float *quat)
   1.321 +{
   1.322 +	Quatf oq = vr_ctx.ovr_sfusion.GetPredictedOrientation();
   1.323 +	quat[0] = oq.x;
   1.324 +	quat[1] = oq.y;
   1.325 +	quat[2] = oq.z;
   1.326 +	quat[3] = oq.w;
   1.327 +}
   1.328 +
   1.329 +extern "C" void vr_get_rotation_euler(float *euler)
   1.330 +{
   1.331 +	Quatf oq = vr_ctx.ovr_sfusion.GetPredictedOrientation();
   1.332 +	oq.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(euler + 1, euler, euler + 2);
   1.333 +}
   1.334 +
   1.335 +extern "C" void vr_draw_eye(int eye, unsigned int tex, float tex_scale_x, float tex_scale_y)
   1.336 +{
   1.337 +	static const float rects[3][4] = {
   1.338 +		{-1, -1, 1, 1},
   1.339 +		{-1, -1, 0, 1},
   1.340 +		{0, -1, 1, 1}
   1.341 +	};
   1.342 +	static const float offs_scale[3] = {0.0, -1.0, 1.0};
   1.343 +
   1.344 +	glPushAttrib(GL_ENABLE_BIT);
   1.345 +	glDisable(GL_DEPTH_TEST);
   1.346 +	glDisable(GL_LIGHTING);
   1.347 +	glEnable(GL_TEXTURE_2D);
   1.348 +
   1.349 +	glMatrixMode(GL_MODELVIEW);
   1.350 +	glPushMatrix();
   1.351 +	glLoadIdentity();
   1.352 +
   1.353 +	glMatrixMode(GL_PROJECTION);
   1.354 +	glPushMatrix();
   1.355 +	glLoadIdentity();
   1.356 +
   1.357 +	glUseProgram(sdrprog);
   1.358 +
   1.359 +	if(sdrprog) {
   1.360 +		int loc;
   1.361 +		if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) {
   1.362 +			float offset = vr_ctx.info.lens_center_offset * offs_scale[eye];
   1.363 +			glUniform1f(loc, offset);
   1.364 +		}
   1.365 +
   1.366 +		if((loc = glGetUniformLocation(sdrprog, "tex_scale")) != -1) {
   1.367 +			glUniform2f(loc, tex_scale_x, tex_scale_y);
   1.368 +		}
   1.369 +	}
   1.370 +
   1.371 +	glBindTexture(GL_TEXTURE_2D, tex);
   1.372 +	glBegin(GL_QUADS);
   1.373 +	glColor4f(1, 1, 1, 1);
   1.374 +	glTexCoord2f(0, 0); glVertex2f(rects[eye][0], rects[eye][1]);
   1.375 +	glTexCoord2f(1, 0); glVertex2f(rects[eye][2], rects[eye][1]);
   1.376 +	glTexCoord2f(1, 1); glVertex2f(rects[eye][2], rects[eye][3]);
   1.377 +	glTexCoord2f(0, 1); glVertex2f(rects[eye][0], rects[eye][3]);
   1.378 +	glEnd();
   1.379 +
   1.380 +	glUseProgram(0);
   1.381 +
   1.382 +	glPopMatrix();
   1.383 +	glMatrixMode(GL_MODELVIEW);
   1.384 +	glPopMatrix();
   1.385 +
   1.386 +	glPopAttrib();
   1.387 +}