OpenGL-Sandbox

 view release on metacpan or  search on metacpan

lib/OpenGL/Sandbox.c  view on Meta::CPAN

			need= width * height * pixel_size;
			if (need > data_len)
				carp_croak("Require at least %d bytes of pixel data (got %d)", need, data_len);
		}
		else if (!SvOK(data_sv) || SvIV(data_sv) == 0) {
			if (xoffset || yoffset) carp_croak("Can't use NULL pixel data when specifying a sub-image");
			data= NULL;
			data_len= 0;
		}
		else
			carp_croak("Expected scalar-ref %sfor data argument", (xoffset || yoffset)? "":"or undef ");
	}
	
	/* TODO: support OpenGL 4.5 which doesn't need to bind to anything */
	if (!tx_id_p || !(tx_id= SvUV(tx_id_p)))
		croak("tx_id must be initialized first");
	glBindTexture(target, tx_id);
	
	if (pitch) {
		/* OpenGL doesn't do row length in bytes, it does it in pixels. This is not helpful. */
		if (!pixel_size)
			croak("Don't know how to apply 'pitch' to pixels of format=%d type=%d", format, type);
		switch (pitch > 0 ? pitch % pixel_size : -1) {
		case 0: pix_align= 1; row_len= pitch / pixel_size; break;
		case 1: if ((pitch & 1) == 0) { pix_align= 2; row_len= pitch / pixel_size; break; }
		case 2:
		case 3: if ((pitch & 3) == 0) { pix_align= 4; row_len= pitch / pixel_size; break; }
		case 4:
		case 5:
		case 6:
		case 7: if ((pitch & 7) == 0) { pix_align= 8; row_len= pitch / pixel_size; break; }
		default:
			croak("Unsupported buffer pitch %d for pixel size %d", pitch, pixel_size);
		}
		glGetIntegerv(GL_UNPACK_ALIGNMENT, &orig_pix_align);
		glGetIntegerv(GL_UNPACK_ROW_LENGTH, &orig_row_len);
	}
	
	/* If xoffset or yoffset are nonzero, then this requires the texture to be loaded already,
	 * and the internal format and mipmap and etc is irrelevant. */
	if (xoffset || yoffset) {
		if (pitch) {
			glPixelStorei(GL_UNPACK_ROW_LENGTH, row_len);
			glPixelStorei(GL_UNPACK_ALIGNMENT, pix_align);
		}
		glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, data);
		if (pitch) {
			glPixelStorei(GL_UNPACK_ROW_LENGTH, orig_row_len);
			glPixelStorei(GL_UNPACK_ALIGNMENT, orig_pix_align);
		}
		return;
	}
	/* Else we are defining the storage for the texture and more things need considered.
	 * Also the texture object should be updated with the result of the calculations below. */
	
	if (internal_p) internal_fmt= SvIV(internal_p);
	else if (known_format) internal_fmt= default_internal_fmt;
	else carp_croak("No default internal_format for given format %d; must be specified", format);
	
	/* use mipmaps if the user set it to true, or if the min_filter uses a mipmap,
	   and default in absence of any user prefs is true. But not if the user has specified 'level' */
	with_mipmaps= level? 0
		: mipmap_p? SvTRUE(mipmap_p)
		: !min_filter_p? 1
		: (SvIV(min_filter_p) == GL_NEAREST || SvIV(min_filter_p) == GL_LINEAR) ? 0
		: 1;
	
	if (with_mipmaps) {
		if (major < 3) {
			glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
			if (mag_filter_p)
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, SvIV(mag_filter_p));
			if (min_filter_p)
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, SvIV(min_filter_p));
		}
	} else if (!level) {
		if (mag_filter_p)
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, SvIV(mag_filter_p));
		/* this one needs overridden even if user didn't request it, because default uses mipmaps */
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_p? SvIV(min_filter_p) : GL_LINEAR);
		/* and inform opengl that this is the only mipmap level */
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
	}
	if (pitch) {
		glPixelStorei(GL_UNPACK_ROW_LENGTH, row_len);
		glPixelStorei(GL_UNPACK_ALIGNMENT, pix_align);
	}
	glTexImage2D(target, level, internal_fmt, width, height, 0, format, type, data);
	if (pitch) {
		glPixelStorei(GL_UNPACK_ROW_LENGTH, orig_row_len);
		glPixelStorei(GL_UNPACK_ALIGNMENT, orig_pix_align);
	}
	if (with_mipmaps && major >= 3) {
		/* glEnable(GL_TEXTURE_2D);  correct bug in ATI, accoridng to Khronos FAQ */
		glGenerateMipmap(GL_TEXTURE_2D);
		/* examples show setting these after mipmap generation.  Does it matter? */
		if (mag_filter_p)
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, SvIV(mag_filter_p));
		if (min_filter_p)
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, SvIV(min_filter_p));
	}
	if (!level) {
		if (wrap_s_p)
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, SvIV(wrap_s_p));
		if (wrap_t_p)
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, SvIV(wrap_t_p));
	}

	/* update attributes */
	if (!hv_store(self, "width",            5, sv=newSViv(width), 0)
	 || !hv_store(self, "height",           6, sv=newSViv(height), 0)
	 || (known_format &&
	    !hv_store(self, "has_alpha",        9, sv=newSViv(has_alpha? 1 : 0), 0))
	 || !hv_store(self, "internal_format", 15, sv=newSViv(internal_fmt), 0)
	 || !hv_store(self, "loaded",           6, sv=newSViv(1), 0)
	) {
		if (sv) sv_2mortal(sv);
		croak("Can't store results in supplied hash");
	}
	return;



( run in 1.809 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )