Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

969 Good

About Vincent_M

  • Rank
    Advanced Member

Personal Information

  • Interests
  1. I forgot to post that. I'm doing basic mipmapping. Here's the member definition that creates the OpenGL texture object, and uploads the data to its memory space: uint32_t Font::CreateTexture(size_t width, size_t height, const void* buffer) { uint32_t handle; glGenTextures(1, &handle); glBindTexture(GL_TEXTURE_2D, handle); glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, (GLsizei)width, (GLsizei)height, 0, GL_RED, GL_UNSIGNED_BYTE, buffer); glGenerateMipmap(GL_TEXTURE_2D); 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_MIPMAP_LINEAR); return handle; } Here's how I call it: texture_ = CreateTexture(atlasWidth_, atlasHeight_, (void*)((uint8_t*)buffer + offset)); Here's my text shader source as well: static const std::string TextVertSource = "uniform mat4 u_transMat;" "attribute vec2 a_pos;" "attribute vec2 a_coord;" "varying vec2 v_coord;" "void main()" "{" " v_coord = a_coord;" " gl_Position = u_transMat * vec4(a_pos, 0.0, 1.0);" "}" ; static const std::string TextFragSource = "uniform vec4 u_params;" // fillWidth, fillEdge, strokeWidth, strokeEdge "uniform vec4 u_colors[2];" // fillColor, strokeColor "uniform sampler2D u_tex;" "varying vec2 v_coord;" "void main()" "{" " float distance = 1.0 - texture2D(u_tex, v_coord).r;" " float fillAlpha = 1.0 - smoothstep(u_params.x, u_params.x + u_params.y, distance);" " float strokeAlpha = 1.0 - smoothstep(u_params.z, u_params.z + u_params.w, distance);" " float a = fillAlpha + (1.0 - fillAlpha) * strokeAlpha;" " vec4 color = mix(u_colors[1], u_colors[0], fillAlpha / a);" " gl_FragColor = color;" " gl_FragColor.a = a;" "}" ;
  2. My SDF font looks great at large sizes, but not when I draw it at smaller sizes. I have my orthogonal projection matrix setup so that each unit is a 1x1 pixel. The text is rendered from Freetype2 to a texture atlas @ 56px with a spread of 8 pixels (the multiplier is 8x and scaled down). I'm drawing @ 18px in the screenshot attached to this post. The way I calculate the size of the text quads is by dividing the desired size (18px in the screenshot) by the size of the glyphs in the atlas (56px in this case), and scaling the glyph sprite by that factor. So: 18/56 = ~0.32, and I multiply the rect's size vector by that when it comes to vertex placement (this obviously doesn't apply to the vertices' texture coords). Now, I made sure that all metrics stored in my SDF font files are whole numbers (rect position/size, bearing amounts, advance, etc), but when I scale the font, vertex positions are almost always not going to be whole numbers. I increase the "edge" smoothstep shader parameter for smaller text as well, but it doesn't seem to help all that much.
  3. Vincent_M

    Real-Time WebSockets and REST

    I debated about this: start now, and ask questions later, or sit back and contemplate. I chose to ask about architecture first, but ended up diving into the project. I initially wanted to ask about jitter, latency and how to combat that with dead reckoning/path interpolation. I've read some papers online, but wanted to go over the specifics of it once I actually had something implemented. I ran into the issue of writing my Asteroids MMO using TCP sockets a few years back. It was a nightmare attempting to convert it to UDP, and I never finished UDP support. The game was plagued by jittering when 2 players weren't playing off of the same access point.   I started writing a REST API for user account management. This allows users to create new accounts, verify them via email, change emails, rename usernames, etc. I'm thinking about using it for login purposes too, but my NodeJS server could handle this as well since it'll have database access as well. At my old job, we would pass an API-KEY key-value pair in each of our REST API's requests. The request would return an error if the call didn't include it with the correct value. I've seen the use of API keys mentioned online, but I don't see the point of using them. Anyway monitoring the API calls via proxy can figure what the key is, so why bother using one? Is this to help stave some type of automated attacks not specifically targeted at my application?   I thought agar.io used WebSockets. Player movement didn't appear to have any jittering unless players broke into smaller pieces since you'd suddenly have a bunch of objects moving much faster onscreen. I'll ask more specific questions when I get to that point. Working on the sign-in system.   I've used both in Python projects at work in the past, but not in PHP yet. I'm considering Redis for sessions, possibly   Perfect! I've wondered if there was a UDP counterpart to WebSockets. I've searched online in the past, but found nothing. When I first read about WebRTC, I also wondered how supported it'd be client-side in browsers, but I think it'll work for my purposes. I'm writing stuff that's meant to be more experimental than mass-supported.   I've wondered about this myself. It seems like WebSockets have been widely supported since 2012.
  4. I want to make a real-time light MMO-like Asteroids game using Unity and WebSockets for the client, and NodeJS, SocketIO and Box2D on the server side. I'll handle scaling by having each instance of my server be a separate "universe" the player can explore.   Players only have a single login for their account, and can jump between available servers, which are considered separate "galaxies". Since the player's account isn't directly tied to any specific server instance, the login mechanism needs to be separate from that, so I've thought about going the REST API route. Once successfully authenticated, my REST API would generate a authentication token to represent their login credentials for their session. Once the player is logged in, they can select a galaxy (server) to visit, provided it hasn't met its player capacity. When the player attempts to connect to that server, the client will pass the player's token, and the server will check if that token is a valid session with the database (this might breach RESTfulness).   If the server finds that the token is valid, a socket connect between the client and server is attempted. Upon success, a player object is created on the server, added to the list of current players. The server will use Box2D, or some type of physics engine to process movement, collision, etc, and report the observable portion of galaxy that the player can see as a message to the client ever few milliseconds (the goal is 30 frames per second). The Unity client will render the observable objects within view to the user. The client will periodically send input signals to the server (again, the goal is 30 fps). Those input signals are interpreted by the server to perform actions, such as steering the ship, shooting projectiles, interacting with the environment, etc. Whenever the client sends a message to the server, it also sends its token that the server uses to ensure that the client connection is coming from something that it originally considered legitimate.   WebSockets is primarily meant to send real-time data in the form of binary data instead of JSON to reduce overhead and serialization/deserialization between the client and server. Unity's .NET implementation appears to support binary serialization/deserialization that could be faster than JsonFX, but I have yet to benchmark it. Packing the database into binary datatypes will be a pain on the NodeJS side, but I plan on going back to a C server once I get things figured out. The server also has access to the database to submit queries such as kills, resources mined, health picked up, score, currency, in-game shop transactions, inventory pick-ups, etc.   The player can also update their player info in-game, send money to users, and other actions that the REST API would handle. As far as database queries go, I'd probably use AWS SQS for a larger-scale design, and have some sort of in-memory database to help with queries happening between what's actually in the database, and what's yet to be in it.   I'd use AWS, and have a server for the REST API, one for the database, and one for each galaxy configuration per instance required. How does this sound as far as architecture?
  5. Vincent_M

    Different Resolutions

    That's a pretty good point. I remember some one mentioning in a thread a while back where he'd play Age of Kings on his 4K display. The largest map sizes could fit entirely onscreen. This could be an advantage or disadvantage to the users depending on how physically large the display is (32-inch vs 60-inch). The was we addressed the varying aspect ratio issue in one of our portrait mobile games was similar to how the Warcraft games did it. We'd use our skinniest aspect ratio (9:16) as our basis aspect ratio to draw all UI elements within. The game would be in full-view, while our widest aspect ratio (3:4) would have decorative borders on the sides. We used a fixed-height Cartesian coordinate system where the origin was at the center of the screen, and the y-axis was facing up rather than down. We'd place all of our UI elements within the bounds of the 9:16 aspect ratio, and add those borders just outside of the 9:16 view. Then, wider aspect ratios would show the border. How much of the border it showed depended on how close to 3:4 we got.   I believe we used a fixed height of 720, or maybe we used 960. In any case, this was only for placement and size (including 9-slicing). We were targeting the iPad retina as our highest possible resolution, so our fullscreen backgrounds were 1536x2048 (3:4). In a 720 fixed-height coordinate space, we get a viewport range of +/-360, which covers 2048 pixels down on a retina iPad.   This can all be accomplished with the projection matrix, as mentioned by IceCave.
  6. Vincent_M

    Career Advice

    I've been really tired today, so I'm struggling to conveying my thoughts.   1. Of course, it'll take more time. I've spent a long time trying to get experience on my own, but it appears that I'm only working harder, not smarter. I can't seem to focus on a single thing.   2. I'm picky because I'm so new to the software engineering industry in general. I don't know what most job roles really are, or even what I want. Not only do I need experience, but I need to figure out what I want that's obtainable right now. Then, I actually know what to work toward.   3. I meant seniors. Most companies are looking for senior developers, not junior developers.   4. I mean not knowledgable in as "uncomfortable." If I see something I might be interested in, should I just go for it? Getting a job in that field could land me a reliable mentor.   5. This warrants a quote: I completely agree. I need more experience in the industry in general, not just programming. I try to balance my programming, gym and family time with a social life too. I'm always meeting people who want to do projects with me. Again, lack of experience and direction on my part's destroyed every personal project I've done to date. I'll post back when I'm done reading your article.
  7. Vincent_M

    Career Advice

    I've been programming as a hobby for well over a decade now, but I've only been programming professionally for 2 years. Due to this, I have access to mentors who know their stuff, but I also have access to some pretty gnarly code bases. I've only worked for small companies during this time. My only work-experience skills are in Unity/C# (some C# development outside of Unity), Python, ActionScript3, and a few libraries within all those.   I have a lot of personal experience in C++, but not in the workplace yet. I also have personal experience with PHP, SQL (I've only used MySQL for the implementation), Java, and Objective-C. I've also got experience with Qt, the Android and iOS SDKs, and a bunch of libraries. I have a degree in Management Information Systems, but I'm at most, junior-level in everything. I'm in my mid-20s, and ambitious like most people my age. Unfortunately, I lack the skills of a seasoned professional. I want to get those skills.   I really want to get a lead developer role in something involving backend or tools development. I really enjoy programming, and try to put in 20 hours into it a week after work and gym. I think I'm decent in C++ and C#, but far from mastery. I've been told I have potential by a potential employer, but results are what they want. I really want to have a sense of mastery when it comes to software design in general.   There are plenty of software development jobs in Las Vegas where I live, but I've become picky on what to apply for. Part of my pickiness comes from lack of experience. Most of my experience is in C++, but everyone wants juniors. Would it be wise to seek out a junior-level job in a field I'm not really comfortable in? I really want to run a small-time video game studio, and make fun games for mobile, and Steam. Again, who wouldn't want that here on these forums? haha
  8. I use "this->" when I have identical names. When assigning variables in the constructor's initializer list, it seems to not make any different that my constructor parameters have identical names to my       Do class fields still get assigned by value when passing by reference, right? One thing that confuses me about references is that I can still pass literals in as parameters. I've just recently started using references, so it's practice at this point. If I wanted to pass objects by value into my constructor (aka, make a copy, just like push_back() does in std::vector), would I not use a reference? If I wanted to pass by reference, would it be wise to use references over pointers, or does it depend on the situation?       I've seen these cases a lot myself in the past. I think the book, Clean Code, suggests not doing this though. I can't remember if I really read that a year ago when I read the book, or even why that'd be the case. Personally, a prefix sounds like a good way to go as, you like said, explicitly establishes scope for that variable throughout the class. I could even have local variables with the same name, but no prefix, and the code wouldn't look as confusing, provided the situation would require a variable named like that. I'm a big fan of just the preceding underscore, which appears to be a common convention in Obj-C, C#, etc. I've been told by a lead developer in the past that a preceding underscore isn't a good practice in C++ while it is in C#.   @Gooey: The code compiled fine, but it does look misleading. I didn't even think about this as I was still thinking in terms of passing-by-value. Trying to go with references over value when I can do that. but you also bring up a good point. A const reference makes it misleading. @Strewya: Good point on the code convention. Removing the const reference sounds like the better way to go.   EDIT: I found this post on why a we shouldn't start variable names with an underscore. Bottom line: variables starting with an underscore is reserved for C++ implementors. Sounds like this goes for variables starting with both upper and lower-case letters after the underscore. Josh Petrie also pointed out in a previous post I started 2 days ago when I was doing that with my header guards. I thought he only meant that for header guards though. After reading that post, it makes all sense now. I guess m_* might be the way to go. This posts suggests using trailing underscores for naming. I kind of like that naming convention.
  9. One issue I frequently run into is trying to come up with decent names for parameter names. This is especially a problem in constructors and setter methods. For example, take the following class: class Car { private: unsigned int gas; unsigned int tankCapacity; float headlightRange; public: Car(const int& gas, const int& tankCapacity, const float& headlightRange = 15.0f) : gas(gas), tankCapacity(tankCapacity), headlightRange(headlightRange) { } void SetGas(const unsigned int& amount) { gas = amount; if(gas > tankCapacity) gas = tankCapacity; } void SetCapacity(const unsigned int& amount) { tankCapacity = amount; if(gas > tankCapacity) gas = tankCapacity; } void SetHeadlightRange(const float& range) { if(range > 0.0f) headlightRange = 0.0f; } }; Ok, so I couldn't come up with any setters where I could only think of a parameter name that matches the field that'd I'd be modifying right now, but it's been an issue for me from time to time. Still, the constructor's a concern.
  10. Vincent_M

    Why NASA Switched from Unity to Blend4Web

    True, some WebGL games are simply too ambitious for mobile, but there are some impressive WebGL demos such as this one on my iPhone 6 Plus at an intractable framerate. As far as large amounts of memory consumption: probably a byproduct of much of everything being in JavaScript --even if running as an IL/emscripten approach. WebGL's currently-supported implementation is the JavaScript equivalent to the OpenGL ES 2.0 API in C, which Unity's supported for some time now. They'd mostly have to use some sort of IL approach, such as JS.asm/emscripten to convert the code-base over to something browsers, even Node.js could run. It sounds like their own IL2CPP is their solution to that. If anything, just switch your platform and renderer to OpenGL ES 2.0, and you've got yourself a natively-written app. Now, your only hurdle is Apple's App Store review process. Sure, there are plenty of hurdles that Unity's got to jump, but their publicly-released efforts regarding WebGL look pretty solid so far.
  11. I override removeRows() to specifically remove scene nodes from my own hierarchy's structure between beginRemoveRows() and endRemoveRows(). It's been a few weeks since I worked on this, but I think removeRows() was being called internally by the base class, QAbstractItemModel, whenever I moved something in my hierarchy. Changing drag and drop operations from InternalMove to DragDrop seemed to stop calling removeRows() internally.   I agree with trying to avoid having to subclass QTreeView for simple operations. You'd think it'd provide more intuitive signals for when selections change and occur, but hey, there are reimplementation methods for that (ugh)! Again, I'm still pretty new to Qt, and it looks like it doesn't directly handle selections, but rather the QSelectionModel field it has does this.   Either way, my hierarchy system appears to work like a charm now. There are only minor changes here, but here's the working source code I've got: #include "SceneModel.h" #include "Scene.h" #include "Node.h" #include <stdio.h> #include <stdlib.h> #include <QKeyEvent> #include <QMimeData> #include <QByteArray> #include <QColor> #include <QDebug> Qt::ItemFlags SceneModel::flags(const QModelIndex &index) const { Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); if(index.isValid()) return defaultFlags | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsEditable; else return defaultFlags | Qt::ItemIsDropEnabled; return QAbstractItemModel::flags(index); } Qt::DropActions SceneModel::supportedDropActions() const { return QAbstractItemModel::supportedDropActions() | Qt::MoveAction; } int SceneModel::rowCount(const QModelIndex &parent) const { // make sure the scene's root node is valid and the parent's column is zero if(!scene || !scene->GetRoot() || parent.column() > 0) return 0; // return the parent's children, if valid if(parent.isValid()) return static_cast<Node*>(parent.internalPointer())->GetNumChildren(); // otherwise, return the children return scene->GetRoot()->GetNumChildren(); } int SceneModel::columnCount(const QModelIndex&) const { return 1; } QModelIndex SceneModel::index(int row, int column, const QModelIndex &parent) const { // make sure the root, row and column data is valid if(!scene || !scene->GetRoot() || !hasIndex(row, column, parent)) return QModelIndex(); // get the parent Node from the index Node *parentItem = scene->GetRoot(); if(parent.isValid()) parentItem = static_cast<Node*>(parent.internalPointer()); Node *childItem = parentItem->GetChild(row); if(childItem) return createIndex(row, column, childItem); return QModelIndex(); } QModelIndex SceneModel::parent(const QModelIndex &index) const { // make sure the index is valid if(!scene || !index.isValid()) return QModelIndex(); // get the child item to get the parent item Node *childItem = static_cast<Node*>(index.internalPointer()); if(!childItem) return QModelIndex(); Node *parentItem = childItem->GetParent(); // return nothing if the parent item is the root if(!parentItem || parentItem == scene->GetRoot()) return QModelIndex(); return createIndex(parentItem->GetChildIndex(), 0, parentItem); } QVariant SceneModel::data(const QModelIndex &index, int role) const { if(!index.isValid()) return QVariant(); if(role == Qt::ForegroundRole) { Node *node = static_cast<Node*>(index.internalPointer()); if(node && !node->IsActive()) return QColor(Qt::gray); return QVariant(); } // handle displaying the data if(role == Qt::DisplayRole || role == Qt::EditRole) { // get the child and parent Node pointers Node *node = static_cast<Node*>(index.internalPointer()); return QString(node->GetName().c_str()); } return QVariant(); } bool SceneModel::submit() { // make sure the scene is available if(scene) { // check if the selected node is valid if(selectedNode) { // get the selected node's index, and update its display data QModelIndex selectedIndex = createIndex(selectedNode->GetChildIndex(), 0, selectedNode); setData(selectedIndex, QString(selectedNode->GetName().c_str()), Qt::DisplayRole); } } return QAbstractItemModel::submit(); } bool SceneModel::setData(const QModelIndex &index, const QVariant &value, int role) { // check if the index is valid, and either in EditRole or DisplayRole mode if(index.isValid() && (role == Qt::EditRole || role == Qt::DisplayRole)) { Node *node = static_cast<Node*>(index.internalPointer()); if(!node) return false; // set the node's new name, and signal that data has changed node->SetName(std::string(value.toString().toUtf8())); emit dataChanged(index, index); // emit signal that specifically signifies that the name has changed if(role == Qt::EditRole) emit SelectedNodeNameUpdated(node->GetName()); return true; } return QAbstractItemModel::setData(index, value, role); } bool SceneModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int, const QModelIndex &parent) { // make sure this is aciton shouldn't be ignored if(!scene || !data || action == Qt::IgnoreAction) return false; // get the encoded data of our Node pointer QByteArray encodedData = data->data(SceneModelMIMEType); Node *node = (Node*)encodedData.toULongLong(); if(!node) return false; // get the parent node QModelIndex destinationParentIndex; Node *parentNode = static_cast<Node*>(parent.internalPointer()); if(parentNode) { destinationParentIndex = parent; } else { parentNode = scene->GetRoot(); destinationParentIndex = createIndex(0, 1, scene->GetRoot()); } // get rowCount if row is invalid (this might be an old Qt bug) if(row == -1) row = parentNode->GetNumChildren(); // move the row Node *sourceParentNode = node->GetParent(); QModelIndex sourceParent = createIndex(sourceParentNode->GetChildIndex(), 0, sourceParentNode); moveRow(sourceParent, node->GetChildIndex(), destinationParentIndex, row); return true; } QStringList SceneModel::mimeTypes() const { QStringList types; types << SceneModelMIMEType; return types; } QMimeData *SceneModel::mimeData(const QModelIndexList &indexes) const { // make sure there's exactly 1 index and it's valid if(indexes.size() != 1 || !indexes[0].isValid()) return nullptr; // get the Node pointer from the index's internal pointer, convert it to quintptr, then to a UTF string quintptr nodeAddress = (quintptr)indexes[0].internalPointer(); QByteArray encodedData(QString::number(nodeAddress).toUtf8()); // allocate mimeData, provide it with encodedData, and return it QMimeData *mimeData = new QMimeData(); mimeData->setData(SceneModelMIMEType, encodedData); return mimeData; } bool SceneModel::insertRows(int row, int count, const QModelIndex &parent) { if(!scene) return false; Node *parentNode = static_cast<Node*>(parent.internalPointer()); if(!parentNode) parentNode = scene->GetRoot(); // make sure a parent node was found before continuing if(parentNode) { // begin inserting rows, and add begin adding uniquely-named fields beginInsertRows(parent, row, row+count-1); // insert nodes for(int i=0;i<count;++i) parentNode->AddChild("New Node"); endInsertRows(); return true; } return QAbstractItemModel::insertRows(row, count, parent); } bool SceneModel::removeRows(int row, int count, const QModelIndex &parent) { if(!scene) return false; Node *parentItem = static_cast<Node*>(parent.internalPointer()); if(!parentItem) parentItem = scene->GetRoot(); // make sure a parent node was found before continuing if(parentItem) { beginRemoveRows(parent, row, row+count-1); parentItem->RemoveChildren(row, count); endRemoveRows(); return true; } return QAbstractItemModel::removeRows(row, count, parent); } bool SceneModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) { Node *sourceParentNode = static_cast<Node*>(sourceParent.internalPointer()); Node *destinationParentNode = static_cast<Node*>(destinationParent.internalPointer()); Node *childNode = sourceParentNode->GetChild(sourceRow); // make sure the child isn't one of the parent nodes if(childNode == sourceParentNode || childNode == destinationParentNode) return false; // if source and destination parents are the same, move elements locally if(sourceParentNode == destinationParentNode) { // only process if a local move is possible if(sourceParentNode->IsMovePossible(sourceRow, count, destinationChild)) { beginMoveRows(sourceParent, sourceRow, sourceRow+count-1, destinationParent, destinationChild); sourceParentNode->MoveChildren(sourceRow, count, destinationChild); endMoveRows(); return true; } } else { // otherwise, move the node under the parent beginMoveRows(sourceParent, sourceRow, sourceRow+count-1, destinationParent, destinationChild); childNode->SetParent(destinationParentNode, destinationChild); endMoveRows(); return true; } return false; } Are you trying to achieve a typical hierarchy-based scene graph with a tree view as well? Also, were you able to get it to work without the mandatory MIME data nonsense? I can see where MIME data is necessary when dragging files from say, Explorer or Finder into your view or items between separate views, but not from within the same view.
  12. Vincent_M

    Code Review

    I've looked at other C++ books recently. I wanted to get one on STL and templates in general. I've heard Effective C++ was a really good one, but wasn't sure which version to get.   This is a really good point you've brought up. After reading how references are like pointers that can't be NULL, it looks like I could still pass NULL/invalid pointers into the reference parameter parameter by pointed value, which will result in a segment fault.   This is another thing I keep going back and forth on. When I started learning C/C++, there were cases where the PSP homebrew community would store their data as POD if they could afford to in an effort to perform less calls to fread() and fwrite(). Again, padding and endianess between environments is a caveat.   As far as this convention goes: if(rotated) { } I actually prefer it that way for bools, pointers and integer values where zero acts as a special use-case versus a non-zero value. The only reason I wrote that as if(rotated > 0) { } is because I thought that'd be a more accepted convention. I'll post more often when I have questions regarding code conventions.
  13. Vincent_M

    Different Resolutions

    As mentioned above, there are many ways to handle this. One way we dealt with this at a video game company I worked at was work in a fixed-height coordinate space. Instead of having all of your coordinates match up to pixels, come up with some arbitrary fixed height value (test it out though). The fixed height will be the domain of your screen's coordinate space. The width would vary between screen sizes, and you could find it by multiplying your fixed height value by the aspect ratio. That said, make sure all of your fullscreen background artwork produced with the height of your fixed-height value, and its width being whatever it is multiplied by your most extreme aspect ratio (most-likely 16:9, if working in landscape). Then, the sides would just be clipped on screens with fuller aspect ratios, most-notably the 4:3 aspect ratio. You'd design most of your UI in the middle of the screen, making sure it fits nicely in 4:3. You could attach certain UI elements to the edges of the screen so that they hug the sides regardless of fullscreen or widescreen aspect ratios. 9-slicing will be a huge part of this as well. A good deal of your panels and other large UI elements would most-likely be percentage-based if you want them to scale with the screen. The beauty here is that your UI is no longer resolution-dependent, and mostly not aspect-ratio dependent. You could get more creative, and have different resolution images for different resolution devices. For example, high-res iamges for Quad HD and 4K displays (many mobile devices are going Quad HD today). You could use lower-resolution versions of your images for lower-resolution devices --something I highly recommend. Lower-resolution devices are generally older devices as resolutions have been increasing almost every year. These older devices won't have the memory, or the GPU bandwidth to support these higher-resolution textures, so I'd suggest having some sort of content pipeline in place that automatically cooks up low-end builds with lower-resolution images.   Regarding having multiple resolutions of your game's assets, I'd use PC games as an example. With varying hardware and screen resolutions, gamers can usually lower graphical settings, such as texture resolutions, if there isn't enough resources to go around.   You can also use techniques mentioned above alongside this process.
  14. Vincent_M

    Code Review

    Sorry if this is tl;dr. It took me 3 hours to write up a response. Took it to heart though.   Quick glance at the code, you pass parameters by value specially std::string, you do not use const anywhere including marking methods which do not change state of an object. Those two things would be give me the impression that you are a junior.     AND       I still struggle with all of these. I can nail a lot of the simple stuff, but I don't most of the time. I've been programming in C++ as an obsessive hobby since I was in middle school, about 11 years ago. That said, I still do consider myself novice. I've started to notice that I need to get feedback from other programmers to grow, otherwise I'll just be stuck in my old ways. I just gotta face that I'm not John Carmack --I'm just a regular guy lol. I'll to ask more questions, and apply the advice in smaller test cases to reinforce what I'm being taught.   I can't thank you all enough for the feedback.
  15. Vincent_M

    Code Review

    I recently interviewed with a CAD-based studio where I live for a C++/Renderer position. The role was to work on their internal 3D rendering code that's written in DX/OpenGL. They asked for a code sample of one of my personal projects. I sent them one of my projects. It's a basic, open source, texture packer application using Qt to provide the UI. It's not much, but at least it's pretty complete. The CEO got back to me about 10 days later, and said I was too junior for their company at this time. They're looking to fill a senior position first, then they'd consider bringing me on to get mentored.   I was only a little disappointed at first, but more curious than anything. I've been programming since middle school, but I'm only 2 years into programming professionally full-time. I've worked in 2 smaller/startup companies in this time. None of my work has been C++ or lower-level rendering-oriented, so it didn't surprise me when they turned me down. I know I'm not the best C++ programmer out there. I'd like to have some one with better knowledge of C++ to point me in the right directly as far as decent C++ practices go. I don't know if there are any good resources for this online, so I wanted to ask for one in this thread, if that's allowed. I'd really appreciate it if anyone could give me feedback. It can be downloaded here. If anything, you'd get a texture packer with source out of it.
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!