Remember that the code described in this post can be retrieved from GitHub using the tag OBJ.
Near the top of the file SDK/chapter3‑1/templateApp.cpp I changed DEBUG_SHADERS to be defined as true rather than 1 (one). This has been discussed before. The value is being used as a logical value rather than as a numeric value when it's passed to the PROGRAM constructor, and, IMHO, true reflects that usage better than using 1 (one) as a "magic number".
The rest of the changes are pretty straight forward. To create an instance of OBJ I changed
obj = OBJ_load(OBJ_FILE, 1);
to
obj = new OBJ(OBJ_FILE, true);
At the other end of the OBJ life cycle in templateAppExit() I changed
OBJ_free(obj);
to
delete obj;
Before going to the next change needed to use the updated OBJ data types I want to point out that the book has a bug in its description of how to calculate the size parameter. The book tells the reader to use
size = objmesh->n_objvertexdata * sizeof(vec3) *
sizeof(vec3);
sizeof(vec3);
The correct computation of size is
size = objmesh->n_objvertexdata *
(sizeof(vec3) + sizeof(vec3));
(sizeof(vec3) + sizeof(vec3));
Of course, both of these statements assume that the code is still using the old definition of the OBJMESH data type. The new OBJMESH data type no longer has the n_objvertexdata member; the new code needs to substitute objvertexdata.size() so the statement becomes
size = objmesh->objvertexdata.size() *
(sizeof(vec3) + sizeof(vec3));
(sizeof(vec3) + sizeof(vec3));
Likewise, the loop in templateAppInit() which creates the vertex attribute buffer (which eventually gets passed to glBufferData()) also needs to replace objmesh‑>n_objvertexdata with objmesh‑>objvertexdata.size().
This covers most of the changes which need to be made to the sample programs chapter3‑1, chapter3‑2, and chapter3‑3. Sample program chapter3‑4 will be covered after I've discussed rewriting the TEXTURE module using classes. The TEXTURE module will be the topic of my next post.
The last changes I need to talk about are to the loops which iterate over the program‑>uniform_map and objmesh‑>objvertexdata entries.
If you look at the code for sample program chapter3‑1 you'll see that beneath the loop in templateAppInit() there is another version of the same loop which has been commented out. The version of the loop which is commented out is called a range for loop. Per the C++ book I'm reading range for loops are part of the (relatively) new C++ 11 standard. As the comment explains I have found that the current version of Xcode (5.x.x) recognizes range for loops even when the developer hasn't enabled the C++ 11 syntax. I don't know if the Android developer tools support C++ 11 yet so I have opted (in the short term) to avoid using range for loops; the author of the book went to a lot of trouble to write code which would run on both iOS, and Android, and (up to a point) I want to preserve that feature. As a software developer I think being able to cover a broader market is a good thing. Still, some will find them useful so I thought I should point out the option.
There is middle ground I could have used to iterate over the values in objmesh‑>objvertexdata; I could have used C++ iterators explicitly instead of implicitly as a range for loop does. In that case the loop might look something like:
for (auto objvertexdata=objmesh->objvertexdata.begin();
objvertexdata!=objmesh->objvertexdata.end();
++objvertexdata) {
index = objvertexdata->vertex_index;
// The code from here to the end of the loop is the
// same as the other implementations.
.
.
.
}
Using an iterator here, IMHO, more clearly defines for the reader what it is that the loop is really processing. It's not processing a sequence of integers; it's processing a sequence of OBJVERTEXDATA objects. Using a range for statement accomplishes the same thing, and is, IMHO, even better because the expression of the loop is more compact than explicitly using the std::vector::begin() and std::vector::end() methods, and, again IMHO, easier to read, too.
If you look at the program_draw_callback() function you'll see that I also used an iterator to process the elements of program‑>uniform_map. This is a necessary change; the code can't use an integer counter to step through the contents of an std::map. Using an iterator with an std::map is a little messier than using an iterator with std::vector because the iterator contains not just the value, but also the key which the code uses to look up the value in the map. I try to clean this up a bit by creating references (aliases) for the key/name (first) and the value (second) portions of the iterator.
[Note: Remember that the key for the uniform_map container is what used to be the name field of the original version of the UNIFORM data type. Details can be found here.]
Like the loop to process objmesh‑>objvertexdata, this loop has below it a range for implemention for comparison which has been commented out.
Going forward you'll see that in most cases I've chosen to use iterators to loop over the contents of std::vector and std::map containers. I think they are much more readable than using an integer counter (of course, integer counters can't be used with std::map containers anyway), and it makes the loops less wordy as I will demonstrate again when I blog about the Chapter 4 sample programs.
[Note: I only included range for versions of the loops in comments for the chapter3‑1 sample program, not in any of the other sample programs. Demonstrating their use once for each of std::vector and std::map should be sufficient for those who are interested.]
In the next post I'll talk about changes needed to implement the TEXTURE data type as a class.
This covers most of the changes which need to be made to the sample programs chapter3‑1, chapter3‑2, and chapter3‑3. Sample program chapter3‑4 will be covered after I've discussed rewriting the TEXTURE module using classes. The TEXTURE module will be the topic of my next post.
The last changes I need to talk about are to the loops which iterate over the program‑>uniform_map and objmesh‑>objvertexdata entries.
If you look at the code for sample program chapter3‑1 you'll see that beneath the loop in templateAppInit() there is another version of the same loop which has been commented out. The version of the loop which is commented out is called a range for loop. Per the C++ book I'm reading range for loops are part of the (relatively) new C++ 11 standard. As the comment explains I have found that the current version of Xcode (5.x.x) recognizes range for loops even when the developer hasn't enabled the C++ 11 syntax. I don't know if the Android developer tools support C++ 11 yet so I have opted (in the short term) to avoid using range for loops; the author of the book went to a lot of trouble to write code which would run on both iOS, and Android, and (up to a point) I want to preserve that feature. As a software developer I think being able to cover a broader market is a good thing. Still, some will find them useful so I thought I should point out the option.
There is middle ground I could have used to iterate over the values in objmesh‑>objvertexdata; I could have used C++ iterators explicitly instead of implicitly as a range for loop does. In that case the loop might look something like:
for (auto objvertexdata=objmesh->objvertexdata.begin();
objvertexdata!=objmesh->objvertexdata.end();
++objvertexdata) {
index = objvertexdata->vertex_index;
// The code from here to the end of the loop is the
// same as the other implementations.
.
.
.
}
Using an iterator here, IMHO, more clearly defines for the reader what it is that the loop is really processing. It's not processing a sequence of integers; it's processing a sequence of OBJVERTEXDATA objects. Using a range for statement accomplishes the same thing, and is, IMHO, even better because the expression of the loop is more compact than explicitly using the std::vector::begin() and std::vector::end() methods, and, again IMHO, easier to read, too.
If you look at the program_draw_callback() function you'll see that I also used an iterator to process the elements of program‑>uniform_map. This is a necessary change; the code can't use an integer counter to step through the contents of an std::map. Using an iterator with an std::map is a little messier than using an iterator with std::vector because the iterator contains not just the value, but also the key which the code uses to look up the value in the map. I try to clean this up a bit by creating references (aliases) for the key/name (first) and the value (second) portions of the iterator.
[Note: Remember that the key for the uniform_map container is what used to be the name field of the original version of the UNIFORM data type. Details can be found here.]
Like the loop to process objmesh‑>objvertexdata, this loop has below it a range for implemention for comparison which has been commented out.
Going forward you'll see that in most cases I've chosen to use iterators to loop over the contents of std::vector and std::map containers. I think they are much more readable than using an integer counter (of course, integer counters can't be used with std::map containers anyway), and it makes the loops less wordy as I will demonstrate again when I blog about the Chapter 4 sample programs.
[Note: I only included range for versions of the loops in comments for the chapter3‑1 sample program, not in any of the other sample programs. Demonstrating their use once for each of std::vector and std::map should be sufficient for those who are interested.]
In the next post I'll talk about changes needed to implement the TEXTURE data type as a class.
No comments:
Post a Comment