How to Convert This Opengl Pointer Math to Swift

How do I convert this OpenGL pointer math to Swift?

In Swift, you can use the generic struct UnsafePointer to perform pointer arithmetic and casting. Swift doesn't have offsetof, but you can work around that cleanly by taking UnsafePointers of the geometryVertex and textureVertex elements directly.

The following code compiles in an iOS playground. I haven't tested it beyond that but I think it'll work:

import OpenGLES
import GLKit

struct TexturedVertex {
var geometryVertex = GLKVector2()
var textureVertex = GLKVector2()
}

struct TexturedQuad {
var bl = TexturedVertex()
var br = TexturedVertex()
var tl = TexturedVertex()
var tr = TexturedVertex()
init() { }
}

var _quad = TexturedQuad()
withUnsafePointer(&_quad.bl.geometryVertex) { (pointer) -> Void in
glVertexAttribPointer(GLuint(GLKVertexAttrib.Position.rawValue),
2, GLenum(GL_FLOAT), GLboolean(GL_FALSE),
GLsizei(sizeof(TexturedVertex)), pointer)
}
withUnsafePointer(&_quad.bl.textureVertex) { (pointer) -> Void in
glVertexAttribPointer(GLuint(GLKVertexAttrib.TexCoord0.rawValue),
2, GLenum(GL_FLOAT), GLboolean(GL_FALSE),
GLsizei(sizeof(TexturedVertex)), pointer)
}

By the way, using CGPoint the way you did in your question is dangerous, because CGFloat changes size depending on your target (32-bit or 64-bit), but GL_FLOAT always means 32-bit. The tutorial you're following was written before 64-bit iOS came out.

Pointers, Pointer Arithmetic, and Raw Data in Swift

If you just want to do it directly, UnsafePointer<T> can be manipulated arithmetically:

   let oldPointer = UnsafePointer<()>
let newPointer = oldPointer + 10

You can also cast a pointer like so (UnsafePointer<()> is equivalent to void *)

   let castPointer = UnsafePointer<MyStruct>(oldPointer)

Swift, OpenGL and glVertexAttribPointer

To replicate the offsetof functionality you just need to know at which byte offset does each field lie in your structure.

In your case, assuming your struct is tightly packed, the first call should receive 0, and the second 4 * GLfloat because that's the size of the first component. I'm not sure how to extract this data directly from the structure, especially since you're using tuples.

To illustrate, your structure:

struct Vertex {
var position: (x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat)
var color: (r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat)
}

is most probably laid out like that:

GLfloat // <-- structure start // <-- position
GLfloat
GLfloat
GLfloat
GLfloat // <-- color
GLfloat
GLfloat
GLfloat

Hence the position lies at offset 0, and color at 4 * GLfloat.


To create a pointer with a value 16, this answer looks relevant:

let ptr = UnsafePointer<()> + 16

So I suppose this should work as well:

let ptr = UnsafePointer<()> + sizeof(GLfloat) * 4

rendering some characters in OpenGL ES 2.x scene

This question is asked a lot because OpenGL does not have built-in support for text fonts. There is a good survey of solutions and discussion here:

http://www.opengl.org/archives/resources/features/fontsurvey/

http://stackoverflow.com/questions/18557535/text-font-rendering-in-opengles-2-ios-coretext-options-and-best-practice

But the easiest solution by far is to use the Print3D class in the PowerVR SDK:

http://www.imgtec.com/powervr/insider/sdkdownloads/index.asp

Are pointers to Objective-C arrays (via a bridging header) allowed?

Are you allowed to pass in data from an objective-c code to a glBuffer?

Why wouldn't you be allowed? Swift has a pointer API (UnsafePointer<T>, UnsafeMutablePointer<T>, etc.) exactly for this purpose. Obviously this is "unsafe" in the sense that the underlying memory the [Objective-]C pointer points to could change at anytime without the Swift pointer knowing. It also has no information about the size of the memory block that it points to.

Any C pointers or arrays can be bridged to Swift (probably as UnsafeMutablePointer<Void> which you will need to cast to your OpenGL type).

You can avoid any risk of referencing invalid memory by dereferencing the pointer (if it is non-nil) and copying the value stored at the pointer to a variable in your Swift application.

Pointer (memory) alignment to 16K in Swift for Metal buffer creation

I believe this should work for you:

var memory:UnsafeMutablePointer<Void> = nil
var alignment:UInt = 0x4000 // 16K aligned
var size:UInt = bufferSize // bufferSize == your buffer size

posix_memalign(&memory, alignment, size)

For reference:

http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_memalign.html

In Swift, how do I add a setter to immutable GLKit vector structs?

You could create a mutating func that replaces the whole self.

extension GLKVector2 {
mutating func setX(_ x: Float) {
self = GLKVector2Make(x, y)
}
}

...

v2.setX(123)

You could create a property as well, but be careful you will need to write your own getter as well, and you can't return self.x there.

var x: Float {
get {
return v.0
// Note:
// 1. you need to use a getter
// 2. you cannot `return x`, otherwise it will be an infinite recursion
}
set {
self = GLKVector2Make(newValue, y)
}
}

Accessing struct data members via pointer arithmetic

Yes, it is undefined behavior.

The data members are not in an array, and thus are NOT guaranteed to be stored back-to-back in contiguous memory, as pointer arithmetic would require. There may be indeterminate padding generated between them.

The correct way would be to access the members individually, eg:

double& Tensor::operator[](int i)
{
switch (i)
{
case 0: return XX;
case 1: return XY;
case 2: return XZ;
case 3: return YX;
case 4: return YY;
case 5: return YZ;
case 6: return ZX;
case 7: return ZY;
case 8: return ZZ;
default: throw std::out_of_range("invalid index");
}
}

Alternatively, if you really want to use array syntax:

double& Tensor::operator[](int i)
{
if ((i < 0) || (i > 8))
throw std::out_of_range("invalid index");

double* arr[] = {
&XX, &XY, &XZ,
&YX, &YY, &YZ,
&ZX, &ZY, &ZZ
};

return *(arr[i]);
}

Or

double& Tensor::operator[](int i)
{
if ((i < 0) || (i > 8))
throw std::out_of_range("invalid index");

static double Tensor::* arr[] = {
&Tensor::XX, &Tensor::XY, &Tensor::XZ,
&Tensor::YX, &Tensor::YY, &Tensor::YZ,
&Tensor::ZX, &Tensor::ZY, &Tensor::ZZ
};

return this->*(arr[i]);
}

Otherwise, use an actual array for the data, and define methods to access the elements:

struct Tensor
{
double data[9];

double& XX() { return data[0]; }
double& XY() { return data[1]; }
double& XZ() { return data[2]; }
double& YX() { return data[3]; }
double& YY() { return data[4]; }
double& YZ() { return data[5]; }
double& ZX() { return data[6]; }
double& ZY() { return data[7]; }
double& ZZ() { return data[8]; }

double& operator[](int i)
{
if ((i < 0) || (i > 8))
throw std::out_of_range("invalid index");
return data[i];
}
};


Related Topics



Leave a reply



Submit