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 UnsafePointer
s 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
Swift: Protocol VS. Struct VS. Class
How to Create a Rounded Rectangle Label in Xcode 7 and Swift 2
How to Get Label Name from Button
How to Enable Only Numeric Digit Keyboard iOS Swift
How to Use a Uisplitviewcontroller in Swift
How to Add Images as Text Attachment in Swift Using Nsattributedstring
iOS - Uinavigationcontroller, Hide Navigationbar
Swift Sending Data from Child View to Parent View Controller
Periodically Call an API with Rxswift
API to Capture Live Photos in iOS9
Infinite Scroll on iOS with Swift
How to Retrieve Image Stored in Firebase to Show It in View Image View
iOS - Send Image to Instagram - Documentinteraction