{"id":2485,"date":"2020-01-03T23:02:16","date_gmt":"2020-01-03T20:02:16","guid":{"rendered":"http:\/\/demensdeum.com\/blog\/?p=2485"},"modified":"2024-12-16T22:32:30","modified_gmt":"2024-12-16T19:32:30","slug":"flipped-world","status":"publish","type":"post","link":"https:\/\/demensdeum.com\/blog\/pt\/2020\/01\/03\/flipped-world\/","title":{"rendered":"Mundo de cabe\u00e7a para baixo"},"content":{"rendered":"<p>Para desenvolver um novo projeto, o Cube Art Project adotou a metodologia Test Driven Development. Nesta abordagem, primeiro \u00e9 implementado um teste para uma funcionalidade espec\u00edfica do aplicativo e, em seguida, a funcionalidade espec\u00edfica \u00e9 implementada. Considero que a grande vantagem desta abordagem \u00e9 a implementa\u00e7\u00e3o das interfaces finais, que s\u00e3o o menos envolvidas poss\u00edvel nos detalhes de implementa\u00e7\u00e3o, antes do in\u00edcio do desenvolvimento da funcionalidade. Com esta abordagem, o teste dita a implementa\u00e7\u00e3o posterior, agregando todos os benef\u00edcios da programa\u00e7\u00e3o contratual, quando as interfaces s\u00e3o contratos para uma implementa\u00e7\u00e3o espec\u00edfica.<br \/>Projeto de Arte Cubo &#8211; Um editor 3D no qual o usu\u00e1rio constr\u00f3i figuras a partir de cubos; n\u00e3o faz muito tempo que esse g\u00eanero era muito popular. Por se tratar de uma aplica\u00e7\u00e3o gr\u00e1fica, resolvi adicionar testes com valida\u00e7\u00e3o de screenshots.<br \/>Para validar as capturas de tela, voc\u00ea precisa obt\u00ea-las do contexto OpenGL, isso \u00e9 feito usando a fun\u00e7\u00e3o glReadPixels. A descri\u00e7\u00e3o dos argumentos da fun\u00e7\u00e3o \u00e9 simples &#8211; posi\u00e7\u00e3o inicial, largura, altura, formato (RGB\/RGBA\/etc.), ponteiro para buffer de sa\u00edda; qualquer pessoa que tenha trabalhado com SDL ou tenha experi\u00eancia com buffers de dados em C simplesmente substituir\u00e1 os argumentos necess\u00e1rios. Entretanto, acho necess\u00e1rio descrever um recurso interessante do buffer de sa\u00edda glReadPixels; os pixels s\u00e3o armazenados nele de baixo para cima, enquanto em SDL_Surface todas as opera\u00e7\u00f5es b\u00e1sicas ocorrem de cima para baixo.<br \/>Ou seja, tendo carregado uma captura de tela de refer\u00eancia de um arquivo png, n\u00e3o consegui comparar os dois buffers diretamente, pois um deles estava de cabe\u00e7a para baixo.<br \/>Para inverter o buffer de sa\u00edda do OpenGL, voc\u00ea precisa preench\u00ea-lo subtraindo a altura da captura de tela para a coordenada Y. No entanto, vale a pena considerar que h\u00e1 uma chance de ultrapassar os limites do buffer se voc\u00ea n\u00e3o subtrair um durante o preenchimento, o que acontecer\u00e1. levar \u00e0 corrup\u00e7\u00e3o da mem\u00f3ria.<br \/>Como sempre tento usar o paradigma OOP de \u201cprograma\u00e7\u00e3o por interfaces\u201d, em vez do acesso direto \u00e0 mem\u00f3ria tipo C por ponteiro, quando tentei escrever dados fora do buffer, o objeto me informou sobre isso gra\u00e7as \u00e0 valida\u00e7\u00e3o de limites no m\u00e9todo .<br \/>O c\u00f3digo final para o m\u00e9todo de obten\u00e7\u00e3o de uma captura de tela no estilo de cima para baixo:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>    auto width = params->width;\n    auto height = params->height;\n\n    auto colorComponentsCount = 3;\n    GLubyte *bytes = (GLubyte *)malloc(colorComponentsCount * width * height);\n    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, bytes);\n\n    auto screenshot = make_shared<Screenshot>(width, height);\n\n    for (auto y = 0; y < height; y++) {\n        for (auto x = 0; x < width; x++) {\n            auto byteX = x * colorComponentsCount;\n            auto byteIndex = byteX + (y * (width * colorComponentsCount));\n            auto redColorByte = bytes[byteIndex];\n            auto greenColorByte = bytes[byteIndex + 1];\n            auto blueColorByte = bytes[byteIndex + 2];\n            auto color = make_shared<Color>(redColorByte, greenColorByte, blueColorByte, 255);\n            screenshot->setColorAtXY(color, x, height - y - 1);\n        }\n    }\n\n    free(bytes);\n\n<\/code><\/pre>\n<\/div>\n<h3>Fontes<\/h3>\n<p><a href=\"https:\/\/community.khronos.org\/t\/glreadpixels-fliped-image\/26561\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/community.khronos.org\/ t\/glreadpixels-fliped-image\/26561<\/a><br \/><a href=\"https:\/\/stackoverflow.com\/questions\/8346115\/why-are-bmps-stored-upside-down\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/stackoverflow.com\/questions\/8346115\/why-are-bmps-stored-upside-down<\/a><\/p>\n<h3>C\u00f3digo fonte<\/h3>\n<p><a href=\"https:\/\/gitlab.com\/demensdeum\/cube-art-project-bootstrap\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/cube- art-project-bootstrap<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Para desenvolver um novo projeto, o Cube Art Project adotou a metodologia Test Driven Development. Nesta abordagem, primeiro \u00e9 implementado um teste para uma funcionalidade espec\u00edfica do aplicativo e, em seguida, a funcionalidade espec\u00edfica \u00e9 implementada. Considero que a grande vantagem desta abordagem \u00e9 a implementa\u00e7\u00e3o das interfaces finais, que s\u00e3o o menos envolvidas poss\u00edvel<a class=\"more-link\" href=\"https:\/\/demensdeum.com\/blog\/pt\/2020\/01\/03\/flipped-world\/\">Continue reading <span class=\"screen-reader-text\">&#8220;Mundo de cabe\u00e7a para baixo&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[61,52],"tags":[143,142,76],"class_list":["post-2485","post","type-post","status-publish","format-standard","hentry","category-techie","category-tutorials","tag-cube-art-project","tag-glreadpixels","tag-opengl","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"pt","enabled_languages":["en","ru","zh","de","fr","ja","pt","hi"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"ru":{"title":true,"content":true,"excerpt":false},"zh":{"title":true,"content":true,"excerpt":false},"de":{"title":true,"content":true,"excerpt":false},"fr":{"title":true,"content":true,"excerpt":false},"ja":{"title":true,"content":true,"excerpt":false},"pt":{"title":true,"content":true,"excerpt":false},"hi":{"title":false,"content":false,"excerpt":false}}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2485","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=2485"}],"version-history":[{"count":11,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2485\/revisions"}],"predecessor-version":[{"id":3925,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2485\/revisions\/3925"}],"wp:attachment":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=2485"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=2485"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=2485"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}