• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.


  • Content count

  • Joined

  • Last visited

Community Reputation

129 Neutral

About Blips

  • Rank
  1. I've been wracking my head trying to figure this out for some time now and it's clear that I need some outside help.   I have some VBOs/IBOs that I render through the following method. Batch objects just group data based on common textures: - (void)render { // if the buffer is empty, don't waste time if ([indexBuffer getCurrentSize] <= 0) return; //binding shared buffer objects glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, [indexBuffer getID]); glBindBuffer(GL_ARRAY_BUFFER, [vertexBuffer getID]); glVertexPointer(3, GL_FLOAT, sizeof(struct Vertex), (char *)NULL + 0); glTexCoordPointer(2, GL_FLOAT, sizeof(struct Vertex), (char *)NULL + 12); glNormalPointer(GL_FLOAT, sizeof(struct Vertex), (char *)NULL + 20); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(struct Vertex), (char *)NULL + 32); DynamicArray *renderBatches = [indexBuffer getRenderBatches]; RenderBatch *batch; for (int i = 0; i < [indexBuffer getActiveBatchCount]; i++) { batch = (RenderBatch *)[renderBatches get:i]; [BufferManager setTextureID:[batch getTextureID]]; // render the subset batch of geometry glDrawElements(GL_TRIANGLES, [batch getIndexCount], GL_UNSIGNED_SHORT, (GLvoid *)[batch getIndexBatchOffset]); } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); } IBOs are setup via: - (void)build { glGenBuffers(1, &bufferID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, NULL, GL_DYNAMIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); curBufferSize = bufferSize; } While VBOs are setup via: - (void)build { glGenBuffers(1, &bufferID); glBindBuffer(GL_ARRAY_BUFFER, bufferID); glBufferData(GL_ARRAY_BUFFER, bufferSize, NULL, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); curBufferSize = bufferSize; } IBOs get data with: - (void)updateData:(GraphicElement *)ge_ { RenderBatch *batch; GLuint textureID; //updating the index offset of the ge [ge_ setIndexOffset:curBufferSize / sizeof(unsigned short)]; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferID); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, curBufferSize, [ge_ getIndexCount] * sizeof(unsigned short), [ge_ getIndices]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // working with render batches textureID = [[[ge_ getElement] getParent] getOpenGLTextureID]; // if first graphic element if (activeBatchCount == 0) { // pseudocode: create first batch } // otherwise try and match new graphic element's texture id with batch already in use else { // pseudocode: find batch with matching texture id, or create new batch } curBufferSize += [ge_ getIndexCount] * sizeof(unsigned short); } VBOs get data from: - (void)updateData:(GraphicElement *)ge_ { glBindBuffer(GL_ARRAY_BUFFER, bufferID); glBufferSubData(GL_ARRAY_BUFFER, curBufferSize, [ge_ getVertexCount] * sizeof(struct Vertex), [ge_ getVertices]); glBindBuffer(GL_ARRAY_BUFFER, 0); curBufferSize += [ge_ getVertexCount] * sizeof(struct Vertex); } Now, for the actual problem: Visually, there are no issues at all. The game renders perfectly and is 100% stable. However, when running the OpenGL ES Analyzer, I get thousands of the following warning: "Your application made a drawing call using a buffer that contains uninitialized data. If a draw call uses uninitialized data, the rendering results are incorrect and unpredictable. One way to fix this issue is to provide the buffer data to any BufferData calls instead of a NULL pointer." Example of Responsible Command column: glDrawElements(GL_TRIANGLES, 1056, GL_UNSIGNED_SHORT, NULL) I'm working with OpenGL ES 1.1 (I plan on moving on to 2.0 or 3.0 for my next game) and the OpenGL instrument was running on an iPad Air with iOS 7.x.   If anyone has any insight into how to correct these warnings, that would be amazingly helpful!
  2. [img]http://www.darkrealmstudios.com/MEDIA/IMAGES/_content/Games/Pandemic25/BannerTitle.png[/img] Pandemic 2.5, an expanded and refined version of my popular flash game Pandemic 2, has hit the App Store today for iPads, iPhones and iPod Touches. So far the response has been great, but since this is my first commercial effort, I'm attempting to branch out and reach as many people as possible [i]without[/i] spending money I don't have on marketing. [img]http://www.darkrealmstudios.com/MEDIA/IMAGES/_content/Games/Pandemic25/touchScreens.jpg[/img] [b]Brief feature highlights:[/b][list] [*]Create your very own custom disease and watch as it spreads across the world through the human population. [*]Combine real symptoms to produce the most infectious and deadly disease the world has ever seen. [*]Select from Viral, Bacterial or Parasitic disease classes based on your play-style. [*]Outmaneuver governments, health organizations and doctors as the human world tries to prevent the spread of your disease through vaccine research, quarantines, body disposal, martial laws and more. [*]Be opportunistic: take advantage of natural disasters whenever and wherever they may strike. [*]Unlock achievements and compare highscores will full Game Center support. [*]Purchase once for just $0.99, and enjoy the game on any of your devices. [/list] More info and screens available on my site: [url="http://www.darkrealmstudios.com/games.php?game=12"]www.darkrealmstudios.com[/url] Link to Pandemic 2.5 in the App Store: [url="http://itunes.apple.com/us/app/pandemic-2.5/id483737492?ls=1&mt=8"]http://itunes.apple....37492?ls=1&mt=8[/url] And a special thank you to GameDev and its members for their insight and help!
  3. [quote name='YogurtEmperor' timestamp='1316936998' post='4865720'] Unbind the texture after you are done creating it to make sure you are not accidentally changing its properties later. [code]glBindTexture( GL_TEXTURE_2D, 0 );[/code] L. Spiro [/quote] Sorry, I forgot to include that line. I already was / am doing that.
  4. [quote name='dpadam450' timestamp='1316908311' post='4865596'] You only need to set it once for each texture. [/quote] So why is it not working unless I re-set it during rendering?
  5. I'm approaching completion on my first OpenGL ES game (yay!) but just recently ran into an odd issue with texture filtering. I was trying to improve the game's performance when linear filtering suddenly broke. Code when creating textures was this: [code] glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); [/code] But now, I'm having to set the texture parameters when binding textures and rendering geometry. Is this normal and was it just a fluke that it was working before?
  6. [quote name='YogurtEmperor' timestamp='1313217383' post='4848531'] You made one based off the link I gave? Be warned: the code he provides, while very helpful for getting a result and understanding all the gotchas, is not particularly fast (and there is a leak of memory when it fails in some cases). My rewrite of his code is over 4 times faster, so if you did use his as a reference, be aware that there is tons of room for improvement. Your 1 second would go below to 0.25 seconds. Suggestions for improving upon his code: Use a faster sort (I use a bottom-up merge sort) and make fewer allocations. Pass buffers down to be reused when you are searching the 3 directions of the triangle strips. L. Spiro [/quote] I read over the article before in the past, and re-read it again but wrote my stripper on my own. I'm not doing much sorting and the results are written as binary data to files which are loaded at the appropriate time when the game is running. So the actual performance of the code is not a huge importance since the binary files are loaded extremely quickly. The actual logic for the stripper is rather simple. It essentially just generates all possible strips for a given mesh and selects the longest strip and keeps repeating until no more free faces are left.
  7. I love it when a plan comes together! After writing my Triangle Stripper program over the course of a few hours, I tested it today and it worked completely in the first try! It runs amazingly quick (about 1 second to strip a model composed of 2400+ vertices) and produces some very large strips. Unfortunately it produces quite a few short strips as well. But most importantly is, the strips that it does generate render 100% perfectly. Compared to the htgen program I was using before, it produces roughly 17% more strips . Now that it works, I can tinker with it and try and eliminating those rogue strips of 1 or 2 faces. [b]edit[/b]: And just an additional small update. My game's performance has now jumped over 26% from using indexed triangles in VBOs. Now I just need to perform some basic frustum culling and I should be set!
  8. Thanks a lot mhagain for your detailed explanation. In the end it's essentially functions like indexed triangles correct? If so I'm not sure it'll provide any performance improvements over what I'm doing already. It's recommended that on the iPhone that actual triangle strips are to be used for optimal performance.
  9. [quote name='mhagain' timestamp='1313102347' post='4847975'] If you're using indexes you don't need degenerate triangles. Just draw with GL_TRIANGLES instead and arrange your indexes so that your strips are concatenated. [/quote] Do you have something I can reference that describes what you're talking about? I've only ever read of concatenating strips using degenerate triangles. I'm not sure how I'd go about doing so in such a way that rendering the data as GL_TRIANGLES would work.
  10. In order to squeeze some increased performance out of iOS devices, I'm working on converting my geometry into indexed triangle strips. I found a program ([url="http://www2.cs.cas.cz/%7Esima/htgen-en.html"]htgen[/url]) that works with wavefront obj files and produces a list of indices to produce triangle strips. Brilliant I thought! But then when I tried rendering the newly generated data, the end result looked worse than this: [img]http://img34.imageshack.us/img34/6213/img0020g.png[/img] Now, initially I knew that I had to connect strips with degenerate triangles, however I had no idea that the number of degenerate triangles between strips were not constant. After spending hours reading up on triangle strips, I finally discovered the winding of a proceeding strip can be altered if the incorrect number of degenerate triangles were inserted in between two strips. I spent a few more hours writing out some basic triangle strips over pages and pages of paper and figured out (or so I thought?) exactly how many degenerate triangles were needed depending upon the previous triangle's number. So please correct me if I'm wrong, but: [b]1)[/b] If I have 4 triangles, defined as the indices 0 1 2 3 4 5, OpenGL will draw 4 triangles in the following order: 0 1 2, 2 1 3, 2 3 4, 4 3 5 (which let's assume is CCW for this example). [b] 2)[/b] When joining two strips, normally only 2 extra indices need to be inserted, generating 4 degenerate triangles. So building on the previous strip, if I were to want to join a new strip consisting of 3 new triangles defined as a strip of 6 7 8 9 10 (triangles 6 7 8, 8 7 9, 8 9 10), the final joined list of indices would look like 0 1 2 3 4 5 [b]5 6[/b] 6 7 8 9 10 where the bolded numbers are the extra inserted vertices creating 4 new degenerate triangles. [b] 3)[/b] If joining two strips, and the first triangle of the new strip is odd (as in, the first strip had 3 triangles, numbered 0, 1 and 2, and now the starting triangle of the 2nd strip is numbered 3) [b]three[/b] additional indices must be inserted in between the two strips generating a total 5 degenerate triangles in order for the winding of the 2nd strip to remain CCW. Now based on what I just outline above, I fixed up my code to insert the correct number of degenerate triangles between strips and got the above image which while [i]is[/i] an improvement over the original, it's still in no way correct (the object should look like Canada and the US). So now I'm stuck and I have to assume that if my above understandings are correct, that the htgen program is not generating strips with consistent winding orders ([b]the objects render perfectly fine if I turn off culling[/b]). If that's the case, it looks like I'll have try generating strips myself because I literally cannot find another suitable application that will generate triangle strips. So in the interest of saving myself even more headache and time spent on writing my own application to generate triangle strips, I wanted to confirm that my understanding of the subject is indeed correct.
  11. [quote name='mhagain' timestamp='1312991821' post='4847194'] [quote name='Brother Bob' timestamp='1312969390' post='4847094']Just clarifying here, because the word "between" is often the source of the confusion when misunderstanding the stride. The stride is [i]the distance from the start of one attribute to the start of the next consecutive entry[/i], not the "empty" space between two consecutive attributes (which would be from the end of one to the beginning of the next). If you have a tightly packed array of an interleaved vertex structure, the stride for all attributes is, as mhagain said, simply the size of the vertex itself; no need for fancy calculations with the individual attributes.[/quote] Said it better than I did. It's actually easier if you use a struct for your vertexes rather than a float array - you'll see the layout in your code clearer, reduces potential for error, offsets are just a small bit of pointer arithmetic, and you can use sizeof (mystruct) for your stride param. [/quote] Yeah I'm already working on changing the small program I wrote converting Wavefront files to binary files to use structs rather than an array of floats. Then I'll do the same changes to the actual game! Thanks guys for help and clarification. It's really appreciated.
  12. [quote name='johnchapman' timestamp='1312954903' post='4847047'] "Stride' should be the same.for each attribite; the size of a whole vertex (sizeof(float) *9 in your case. Also, how are you counting RGBA as one float? [/quote] Oh I thought stride was spacing in bytes between two like components (so the bytes between two repetitions of normal data for example). I tried treating the one float for the RGBA data as 4 separate bytes, and hoped that OpenGL would be able to work with it given I've specified color to be unsigned bytes. There's a good chance I'll have to change it I'm guessing though. I'll try making your suggested changes.
  13. I'm currently attempting to get vertex buffer objects to work with interleaved data for indexed triangles. I've manually confirmed that both the index data and the actual vertex data is correct [i]prior[/i] to being loaded into their appropriate buffer objects. The array holding the index data is simply an array of unsigned shorts. The vertex array is an array of floats with the following format (with each bracket symbolizing a float): [vect x][vect y][vect z] [texture u][texture v] [norm x][norm y][norm z] [r g b a] In total, each vertex in array is a series of 9 floats. I have the following offsets and strides as: [code] newMesh.vertexOffset = 0; newMesh.vertexStride = sizeof(GLfloat) * 6; newMesh.uvOffset = sizeof(GLfloat) * 3; newMesh.uvStride = sizeof(GLfloat) * 7; newMesh.normalOffset = sizeof(GLfloat) * 5; newMesh.normalStride = sizeof(GLfloat) * 6; newMesh.colorOffset = sizeof(GLfloat) * 8; newMesh.colorStride = sizeof(GLfloat) * 8; [/code] Here is where and how I create the buffer objects. I was originally using glMapBufferOES() but replaced it with a simpler solution in an attempt to find what is wrong. The arrays being passed into the objects are allocated dynamically, but I'm unsure if I should free them after having passed them to the buffer objects. [code] glGenBuffers(1, &vertexBufferID); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glBufferData(GL_ARRAY_BUFFER, vertexBufferSize, vertexBufferList, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); //creating index buffer object glGenBuffers(1, &indexBufferID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSize, indexBufferList, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); [/code] The buffer sizes have been checked and rechecked and are correct. And here is how I actually go about attempting to render the content. It's probably safe to ignore the texture code block but I included it just in case: [code] glPushMatrix(); glTranslatef(tempMeshInstance.x ,tempMeshInstance.y, tempMeshInstance.z); glRotatef(tempMeshInstance.rotX, 1.0f, 0.0f, 0.0f); glRotatef(tempMeshInstance.rotY, 0.0f, 1.0f, 0.0f); glRotatef(tempMeshInstance.rotZ, 0.0f, 0.0f, 1.0f); glScalef(tempMeshInstance.scaleX, tempMeshInstance.scaleY, tempMeshInstance.scaleZ); //binding vertices glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tempMeshInstance.meshPtr.indexBufferID); //binding vertex buffer objects glBindBuffer(GL_ARRAY_BUFFER, tempMeshInstance.meshPtr.vertexBufferID); //passing the mesh instance data to OpenGL glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, tempMeshInstance.material); glVertexPointer(3, GL_FLOAT, tempMeshInstance.meshPtr.vertexStride, ((char *)NULL + (tempMeshInstance.meshPtr.vertexOffset))); glTexCoordPointer(2, GL_FLOAT, tempMeshInstance.meshPtr.uvStride, ((char *)NULL + (tempMeshInstance.meshPtr.uvOffset))); glNormalPointer(GL_FLOAT, tempMeshInstance.meshPtr.normalStride, ((char *)NULL + (tempMeshInstance.meshPtr.normalOffset))); glColorPointer(4, GL_UNSIGNED_BYTE, tempMeshInstance.meshPtr.colorStride, ((char *)NULL + (tempMeshInstance.meshPtr.colorOffset))); //working with textures if (tempMeshInstance.meshPtr.textureID != prevTextureID && tempMeshInstance.meshPtr.textureID != 0) { glBindTexture(GL_TEXTURE_2D, tempMeshInstance.meshPtr.textureID); //if 2d texturing is disabled, renable it if (!glIsEnabled(GL_TEXTURE_2D)) glEnable(GL_TEXTURE_2D); } else if (tempMeshInstance.meshPtr.textureID == 0 && glIsEnabled(GL_TEXTURE_2D)) glDisable(GL_TEXTURE_2D); prevTextureID = tempMeshInstance.meshPtr.textureID; //rendering the mesh instance glDrawElements(tempMeshInstance.meshPtr.renderFormat, tempMeshInstance.meshPtr.indices, GL_UNSIGNED_SHORT, ((char *)NULL + (0))); //popping the matrix off the stack glPopMatrix(); //continuing through list gameObjs = gameObjs.nextNode; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); [/code] And this is the lovely rendering I'm rewarded with: [img]http://img204.imageshack.us/img204/7107/img0019o.png[/img] Which looks nothing like what the actual object used to look like. So in summary, I don't know if the buffer objects are somehow becoming corrupted, or if I'm incorrectly using the buffer objects (strides and offsets?), or if I'm incorrectly creating the buffer objects, but something is clearly wrong. And clues or hints as to what may be causing this would be more than welcome!
  14. OpenGL

    [b]Mystery solved: [/b]It turns out the normal data in the file was incorrect. I don't know if that is a result of it having been converted from an FBX to a Wavefront Obj file, or if the normals were never good to begin with for some reason. At any rate, I calculated my own normals as I loaded in the vertex data and got a result that looks correct. I'm guessing I'll have to average the normals of each vertex to help smooth the lighting. Here's what it looks like now (along with me rendering lines representing normals for each face): [img]http://img405.imageshack.us/img405/2379/img0016b.png[/img] Thanks for all the help!
  15. OpenGL

    I think I may have spoken too soon of having fixed the issue of only one side being lit. I've made the light directional as it was supposed to be, and after quite a bit of tinkering had thought I had fixed the issue by resetting the position of the light each frame. But then I read (and maybe OpenGL ES is different?) that the light position only changes when being set, and is transformed by the current modelview matrix. My original idea was that the light was orbiting the origin as the model rotated which prevented one side from ever being lit - but now this explination doesn't make sense. I'm pretty sure the normals are correct (I've double confirmed they're being loaded properly) and am going to investigate them more fully today. After a lot of head ache, I've finally managed to get depth buffering working - I had a problem where I was passing a positive value into glOrthof for zNear, and a negative value for zFar. I'm still not sure why switching the values makes sense since objects with a negative z value are further away, but swapping the values got the depth buffering working. I've also got colors and materials in now. Not a huge accomplishment I know, but when coupled with depth buffering helps more clearly illustrate the issue where one side isn't being lit. I've taken new screenshots of the model being rotated about the x axis: [img]http://img717.imageshack.us/img717/5826/seq0.png[/img] [img]http://img594.imageshack.us/img594/9808/seq1.png[/img]